├── .dockerignore ├── .gitattributes ├── .github ├── containerscan │ └── allowedlist.yaml ├── dependabot.yml └── workflows │ ├── check-manual-dependencies.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── EXAMPLES.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── TESTS.md ├── dev ├── .gitignore ├── builder.local.Dockerfile └── generate-local.Dockerfile.sh ├── doc ├── generate-docs.sh ├── generated.usage.txt ├── template.EXAMPLES.md └── template.README.md ├── release ├── .cache │ └── .gitignore ├── .gitignore ├── 0-get-latest-dependencies-versions.sh ├── 10-ensure-protoc-binaries-exist.sh ├── 10.1-get-protoc-binaries.sh ├── 100-check-latest-versions.sh ├── 101-save-latest-versions.sh ├── 20-install-go.sh ├── 30-build-go-archive.sh ├── 40-generate-Dockerfile.sh ├── builder.Dockerfile ├── final.Dockerfile ├── source.sh └── versions.txt ├── src ├── bundled.go ├── errorHandling.go ├── executables.go ├── flags.go ├── go.mod ├── go.sum ├── httpRequest.go ├── protoConversions.go ├── protoRegistry.go ├── protocurl.go └── stdout.go ├── template.goreleaser.yaml └── test ├── payloads ├── invalid.txt ├── payload.json └── payload.txt ├── proto ├── happyday.proto └── nameClashTest.proto.inactive ├── results ├── .gitignore ├── additional-curl-args--X_GET-expected.txt ├── additional-curl-args-expected.txt ├── additional-curl-args-no-curl-expected.txt ├── additional-curl-args-verbose--X_GET-expected.txt ├── additional-curl-args-verbose-expected.txt ├── display-binary-and-headers--X_GET-expected.txt ├── display-binary-and-headers-expected.txt ├── display-binary-and-headers-no-curl-expected.txt ├── echo-empty--X_GET-expected.txt ├── echo-empty--X_GET_-v-expected.txt ├── echo-empty--X_HEAD-expected.txt ├── echo-empty--X_HEAD_--no-curl-expected.txt ├── echo-empty--X_HEAD_-v-expected.txt ├── echo-empty-expected.txt ├── echo-empty-no-curl-expected.txt ├── echo-empty-with-curl-args--X_GET-expected.txt ├── echo-empty-with-curl-args-expected.txt ├── echo-empty-with-curl-args-no-curl-expected.txt ├── echo-filled--X_GET-expected.txt ├── echo-filled-expected.txt ├── echo-filled-no-curl-expected.txt ├── echo-full--X_GET-expected.txt ├── echo-full-expected.txt ├── echo-full-json--X_GET-expected.txt ├── echo-full-json-expected.txt ├── echo-full-no-curl-expected.txt ├── echo-quiet--X_GET-expected.txt ├── echo-quiet-expected.txt ├── echo-quiet-no-curl-expected.txt ├── empty-day-epoch-time-thursday--X_GET-expected.txt ├── empty-day-epoch-time-thursday-expected.txt ├── empty-day-epoch-time-thursday-missing-curl--X_GET-expected.txt ├── empty-day-epoch-time-thursday-missing-curl-expected.txt ├── empty-day-epoch-time-thursday-missing-curl-no-curl-expected.txt ├── empty-day-epoch-time-thursday-no-curl-expected.txt ├── failure-simple--X_GET-expected.txt ├── failure-simple-expected.txt ├── failure-simple-no-curl-expected.txt ├── failure-simple-quiet--D-expected.txt ├── failure-simple-quiet--X_GET-expected.txt ├── failure-simple-quiet--v-expected.txt ├── failure-simple-quiet-expected.txt ├── failure-simple-quiet-no-curl-expected.txt ├── failure-simple-silent--D-expected.txt ├── failure-simple-silent--X_GET-expected.txt ├── failure-simple-silent--q-expected.txt ├── failure-simple-silent--v-expected.txt ├── failure-simple-silent-expected.txt ├── failure-simple-silent-no-curl-expected.txt ├── far-future--X_GET-expected.txt ├── far-future-expected.txt ├── far-future-json--X_GET-expected.txt ├── far-future-json--v-expected.txt ├── far-future-json-expected.txt ├── far-future-no-curl-expected.txt ├── global-protoc--X_GET-expected.txt ├── global-protoc-and-lib--X_GET-expected.txt ├── global-protoc-and-lib-expected.txt ├── global-protoc-expected.txt ├── help--X_GET-expected.txt ├── help-expected.txt ├── help-missing-curl--X_GET-expected.txt ├── help-missing-curl-expected.txt ├── help-missing-curl-no-curl-expected.txt ├── help-no-curl-expected.txt ├── in-wrong--X_GET-expected.txt ├── in-wrong-expected.txt ├── infer-files-provide-file-wrong-args--X_GET-expected.txt ├── infer-files-provide-file-wrong-args-expected.txt ├── inferred-message-package-path--X_GET-expected.txt ├── inferred-message-package-path-expected.txt ├── inferred-message-package-path-name-clash-ambiguous-error--X_GET-expected.txt ├── inferred-message-package-path-name-clash-ambiguous-error-expected.txt ├── inferred-message-package-path-name-clash-explicit-path--X_GET-expected.txt ├── inferred-message-package-path-name-clash-explicit-path-expected.txt ├── inferred-message-package-path-nested--X_GET-expected.txt ├── inferred-message-package-path-nested-expected.txt ├── inferred-message-package-path-nested-subdir--X_GET-expected.txt ├── inferred-message-package-path-nested-subdir-expected.txt ├── inferred-proto-file--F-expected.txt ├── inferred-proto-file--F_-X_GET-expected.txt ├── inferred-proto-file--X_GET-expected.txt ├── inferred-proto-file-expected.txt ├── inferred-proto-file-message-package-path--X_GET-expected.txt ├── inferred-proto-file-message-package-path-expected.txt ├── invalid-protofile-dir--X_GET-expected.txt ├── invalid-protofile-dir-expected.txt ├── invalid-protofile-path--X_GET-expected.txt ├── invalid-protofile-path-expected.txt ├── json-in--X_GET-expected.txt ├── json-in-expected.txt ├── json-in-proper-proto-names--X_GET-expected.txt ├── json-in-proper-proto-names-expected.txt ├── json-in-text-output--X_GET-expected.txt ├── json-in-text-output-expected.txt ├── json-in-wrong-arg--X_GET-expected.txt ├── json-in-wrong-arg-expected.txt ├── json-out-pretty--X_GET-expected.txt ├── json-out-pretty-expected.txt ├── message-package-path-nested-subdir--X_GET-expected.txt ├── message-package-path-nested-subdir-expected.txt ├── message-package-path-resolved-to-non-message-error--X_GET-expected.txt ├── message-package-path-resolved-to-non-message-error-expected.txt ├── missing-args--X_GET-expected.txt ├── missing-args-expected.txt ├── missing-args-no-curl-expected.txt ├── missing-args-partial--X_GET-expected.txt ├── missing-args-partial-expected.txt ├── missing-args-partial-no-curl-expected.txt ├── missing-curl-header-args-not-possible--X_GET-expected.txt ├── missing-curl-header-args-not-possible-expected.txt ├── missing-curl-no-curl--X_GET-expected.txt ├── missing-curl-no-curl-expected.txt ├── missing-protoc--X_GET-expected.txt ├── missing-protoc-expected.txt ├── missing-protoc-global--X_GET-expected.txt ├── missing-protoc-global-expected.txt ├── missing-protocurl-internal--X_GET-expected.txt ├── missing-protocurl-internal-expected.txt ├── moved-curl--X_GET-expected.txt ├── moved-curl-expected.txt ├── moved-curl-no-curl-expected.txt ├── moved-lib--X_GET-expected.txt ├── moved-lib-expected.txt ├── no-default-headers-with-custom-content-type-header--X_GET-expected.txt ├── no-default-headers-with-custom-content-type-header-expected.txt ├── no-default-headers-with-no-additional-headers--X_GET-expected.txt ├── no-default-headers-with-no-additional-headers-expected.txt ├── no-default-headers-with-no-curl-flag--X_GET-expected.txt ├── no-default-headers-with-no-curl-flag-expected.txt ├── no-reason--X_GET-expected.txt ├── no-reason-curl-expected.txt ├── no-reason-expected.txt ├── other-days-are-happy-days--X_GET-expected.txt ├── other-days-are-happy-days-expected.txt ├── other-days-are-happy-days-moved-protofiles--X_GET-expected.txt ├── other-days-are-happy-days-moved-protofiles-expected.txt ├── other-days-are-happy-days-moved-protofiles-no-curl-expected.txt ├── other-days-are-happy-days-no-curl-expected.txt ├── out-wrong--X_GET-expected.txt ├── out-wrong-expected.txt ├── payload-file-not-found-expected.txt ├── payload-invalid-expected.txt ├── payload-json--v-expected.txt ├── payload-json-expected.txt ├── payload-json-relative-expected.txt ├── payload-txt-expected.txt ├── quiet-with-content--X_GET-expected.txt ├── quiet-with-content-expected.txt ├── quiet-with-content-no-curl-expected.txt ├── response-type-arg-inferred-decode-raw--X_GET-expected.txt ├── response-type-arg-inferred-decode-raw-expected.txt ├── response-type-arg-overidden-decode-raw--X_GET-expected.txt ├── response-type-arg-overidden-decode-raw-expected.txt ├── silent-with-content--X_GET-expected.txt ├── silent-with-content-expected.txt ├── silent-with-content-no-curl-expected.txt ├── text-in--X_GET-expected.txt ├── text-in-expected.txt ├── text-in-json-output--X_GET-expected.txt ├── text-in-json-output-expected.txt ├── text-in-wrong-arg--X_GET-expected.txt ├── text-in-wrong-arg-expected.txt ├── tmp-file-permissions-readable--X_GET-expected.txt ├── tmp-file-permissions-readable-expected.txt ├── unknown-base-message-name-error--X_GET-expected.txt ├── unknown-base-message-name-error-expected.txt ├── unknown-message-as-json--X_GET-expected.txt ├── unknown-message-as-json-expected.txt ├── unknown-message-as-text--X_GET-expected.txt ├── unknown-message-as-text-expected.txt ├── unknown-message-package-path-error--X_GET-expected.txt ├── unknown-message-package-path-error-expected.txt ├── verbose-custom-headers--X_GET-expected.txt ├── verbose-custom-headers-expected.txt ├── verbose-custom-headers-no-curl-expected.txt ├── verbose-expected.txt ├── verbose-long-args-equals-args--X_GET-expected.txt ├── verbose-long-args-equals-args-expected.txt ├── verbose-missing-curl--X_GET-expected.txt ├── verbose-missing-curl-expected.txt ├── verbose-no-curl-expected.txt ├── version--X_GET-expected.txt ├── version-expected.txt ├── version-no-curl-expected.txt ├── wednesday-is-not-a-happy-day--X_GET-expected.txt ├── wednesday-is-not-a-happy-day--X_POST-expected.txt ├── wednesday-is-not-a-happy-day-expected.txt ├── wednesday-is-not-a-happy-day-json--X_GET-expected.txt ├── wednesday-is-not-a-happy-day-json-expected.txt ├── wednesday-is-not-a-happy-day-json-no-curl-expected.txt ├── wednesday-is-not-a-happy-day-no-curl-expected.txt ├── without-input--X_GET-expected.txt ├── without-input--X_GET_--no-curl-expected.txt ├── without-input--X_GET_-i___HappyDayRequest-expected.txt ├── without-input--i___HappyDayRequest-expected.txt ├── without-input-expected.txt ├── without-request-type--X_GET-expected.txt └── without-request-type-expected.txt ├── servers ├── .dockerignore ├── Dockerfile ├── compose.yml ├── native-start-server.ps1 ├── package-lock.json ├── package.json ├── server.ts └── tsconfig.json └── suite ├── .gitignore ├── copy-test-results-output-to-expected.sh ├── linux ├── install-test-remove.sh ├── package-alpine.sh └── package-debian.sh ├── native-tests.ps1 ├── setup.sh ├── test.sh └── testcases.json /.dockerignore: -------------------------------------------------------------------------------- 1 | release/tmp/*.zip 2 | .git 3 | release/.cache 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | test/results/*.txt text eol=lf 2 | **/*.md text eol=lf 3 | **/**.sh text eol=lf 4 | -------------------------------------------------------------------------------- /.github/containerscan/allowedlist.yaml: -------------------------------------------------------------------------------- 1 | general: 2 | vulnerabilities: 3 | - CVE-2021-3999 4 | - CVE-2022-2097 # only affects 32-bit x86 platforms. We don't offer this architecture in docker however. 5 | - CVE-2023-0464 # only affects us, if user explicitly passes "-policy" to curl. We simply accept that case. 6 | - CVE-2023-0465 # same as above (CVE-2023-0464) 7 | - CVE-2023-0466 # only applies when X509_V_FLAG_POLICY_CHECK is set as a flag. curl cannot be invoked in protocurl this way. 8 | bestPracticeViolations: 9 | - DKL-LI-0001 10 | - CIS-DI-0005 11 | - CIS-DI-0006 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "daily" 10 | 11 | - package-ecosystem: "gomod" 12 | directory: "/src" 13 | schedule: 14 | interval: "daily" 15 | 16 | - package-ecosystem: "npm" 17 | directory: "/test/servers" 18 | schedule: 19 | interval: "monthly" 20 | -------------------------------------------------------------------------------- /.github/workflows/check-manual-dependencies.yml: -------------------------------------------------------------------------------- 1 | name: Check manual dependencies 2 | 3 | on: 4 | schedule: 5 | - cron: "25 3 4 * *" # monthly: At 03:25 on day-of-month 4 6 | workflow_dispatch: # Allow manual run 7 | 8 | jobs: 9 | check-dependencies: 10 | runs-on: ubuntu-latest 11 | 12 | outputs: 13 | check-outcome: ${{ steps.check.outcome }} 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Check versions of manually managed dependencies 18 | id: check 19 | # We want to be able to react, if the check fails due to a new version. 20 | continue-on-error: true 21 | run: | 22 | ./release/100-check-latest-versions.sh 23 | 24 | create-pull-request: 25 | runs-on: ubuntu-latest 26 | needs: check-dependencies 27 | 28 | if: ${{ needs.check-dependencies.outputs.check-outcome == 'failure' }} 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | with: 33 | ssh-key: ${{ secrets.NEW_PULL_REQUEST_KEY }} 34 | 35 | - name: Create changes 36 | run: | 37 | ./release/101-save-latest-versions.sh 38 | 39 | # Extract newly added lines in diff and combine into commit message part 40 | CHANGED_VERSIONS="$(git diff | grep -e '^\+[^\+]' | sed 's/^+//g' | paste -sd ',' | sed 's/,/, /g')" 41 | CHANGED_VERSIONS_BRANCH="autoupdate/$(echo "$CHANGED_VERSIONS" | sed 's/, /_/g' | sed 's/ /-/g')" 42 | 43 | echo "CHANGED_VERSIONS=$CHANGED_VERSIONS" >> $GITHUB_ENV 44 | echo "CHANGED_VERSIONS_BRANCH=$CHANGED_VERSIONS_BRANCH" >> $GITHUB_ENV 45 | 46 | - name: Create Pull Request and conditionally auto-merge 47 | uses: peter-evans/create-pull-request@v7 48 | id: pull-request 49 | with: 50 | title: "[AutoUpdate] ${{ env.CHANGED_VERSIONS }}" 51 | commit-message: "[AutoUpdate] ${{ env.CHANGED_VERSIONS }}" 52 | branch: ${{ env.CHANGED_VERSIONS_BRANCH }} 53 | delete-branch: true 54 | body: | 55 | New versions of one or more dependencies were found and combined into this pull request. 56 | 57 | If there are notable changes in the dependencies' changelogs, then please create a new release. 58 | 59 | - name: Automatically merge when tests pass 60 | uses: peter-evans/enable-pull-request-automerge@v3 61 | with: 62 | pull-request-number: ${{ steps.pull-request.outputs.pull-request-number }} 63 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Setup 18 | run: | 19 | sudo apt-get -q update 20 | sudo apt-get -q install -y jq zip unzip curl 21 | git fetch --tags origin 22 | 23 | - name: Tests 24 | run: | 25 | ./test/suite/test.sh "$PWD" 26 | 27 | - name: Check Docs 28 | run: | 29 | ./doc/generate-docs.sh "$PWD" 30 | 31 | # "Only a single line diff in EXMAPLES.md is allowed due to non-constant HTTP Date Header." 32 | EXPECTED_DIFF="$(echo -e "1\t1\tEXAMPLES.md")" 33 | # We need to use tabs here, as otherwise the test below would fail. 34 | 35 | if [ "$(git diff --numstat 2>/dev/null)" == "$EXPECTED_DIFF" ]; then 36 | echo "Docs are up to date." 37 | else 38 | echo "The autogenerated docs are not up to date. Generated docs are different from what is commited." 39 | echo "Please run " 40 | echo " doc/generate-docs.sh \"\$PWD\"" 41 | echo "locally, inspect the diff and commit them if they are OK." 42 | echo "================ Git Diff (short) ==================" 43 | git diff --numstat 44 | echo "================ Git Diff (long) ==================" 45 | git diff 46 | exit 1 47 | fi 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Diagnostic reports (https://nodejs.org/api/report.html) 7 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Compiled binary addons (https://nodejs.org/api/addons.html) 16 | build/Release 17 | 18 | # Dependency directories 19 | node_modules/ 20 | 21 | # Optional npm cache directory 22 | .npm 23 | 24 | # Optional eslint cache 25 | .eslintcache 26 | 27 | # Output of 'npm pack' 28 | *.tgz 29 | 30 | # dotenv environment variables file 31 | .env 32 | .env.test 33 | 34 | # IntelliJ 35 | .idea 36 | 37 | # GoReleaser 38 | dist/ 39 | # template output 40 | .goreleaser.yaml 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | Copyright (c) 2022-2025, Ayake Sahoo, QAware GmbH 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 7 | persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 10 | Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 13 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 15 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | The following list acknowledges the bundled dependencies used: 18 | 19 | Google Protobuf, https://github.com/protocolbuffers/protobuf 20 | 21 | Copyright 2008 Google Inc. All rights reserved. 22 | 23 | Redistribution and use in source and binary forms, with or without 24 | modification, are permitted provided that the following conditions are 25 | met: 26 | 27 | * Redistributions of source code must retain the above copyright 28 | notice, this list of conditions and the following disclaimer. 29 | 30 | * Redistributions in binary form must reproduce the above 31 | copyright notice, this list of conditions and the following disclaimer 32 | in the documentation and/or other materials provided with the 33 | distribution. 34 | 35 | * Neither the name of Google Inc. nor the names of its 36 | contributors may be used to endorse or promote products derived from 37 | this software without specific prior written permission. 38 | 39 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 40 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 41 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 42 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 43 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 45 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 49 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | 51 | Code generated by the Protocol Buffer compiler is owned by the owner 52 | of the input file used when generating it. This code is not 53 | standalone and requires a support library to be linked with it. This 54 | support library is itself covered by the above license. 55 | ``` 56 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | We use [GoReleaser](https://goreleaser.com/) to create static binaries and Docker Buildx to build multi-architecture 4 | images. 5 | 6 | The relevant configuration for the release process is in [template.goreleaser.yml](template.goreleaser.yaml) 7 | and [release/source.sh](release/source.sh). It **automatically** fetches the **latest** Go, Goreleaser and Protobuf 8 | versions via GitHub API. 9 | 10 | See also the [.github/workflows/release.yml](.github/workflows/release.yml). 11 | 12 | ## Development 13 | 14 | To make changes to the release process, first [install GoReleaser](https://goreleaser.com/install/). 15 | 16 | You can now inspect the script files and actions used by the GitHub Release Action and change them. 17 | 18 | The script files also show alternative commands that can be used, when developing the release process locally. 19 | 20 | ## Release Process 21 | 22 | The release process works by manually running the **Release** workflow on GitHub. There one needs to provide the 23 | version (e.g. 1.2.3 or 1.2.3-next) for the new release. The corresponding commit will be tagged correspondingly (e.g. 24 | v1.2.3). A new release should first be a release candidate, e.g. `1.2.3-rc` - and only when the workflow passes for the 25 | release candidate - then the same commit should be properly released as `1.2.3`. 26 | 27 | The release process works like this: 28 | 29 | * the [Google Protobuf Binaries](https://github.com/protocolbuffers/protobuf/releases) for the specified PROTOC_VERSION 30 | are downloaded 31 | * Goreleaser is used to cross-compile and build binaries as well as create the archives for the GitHub release and the 32 | doker images 33 | * [Docker Buildx](https://docs.docker.com/engine/reference/commandline/buildx/) is used to build multi-architecture 34 | images and push them to [qaware/protocurl](https://hub.docker.com/r/qaware/protocurl) 35 | * their Dockerfile is generated via [release/40-generate-Dockerfile.sh](release/40-generate-Dockerfile.sh) 36 | * There is a [hack](release/final.Dockerfile), when copying the proper lib files via multi-stage builds and build args into the [distroless cc](https://github.com/GoogleContainerTools/distroless/tree/main/cc) image. 37 | * Native tests for multiple platforms are run. If these tests fail then the release candidate needs to be fixed. 38 | * This should only happen for release candidates - as proper releases should only be created once a release candidate 39 | passes all tests. 40 | 41 | After fixing the code and the tests, a release candidate's tag can be overwritten by setting the option `force` 42 | to `force-reuse-tag` when invoking the workflow. This should only be used when a release candidate is released again 43 | should be overwritten. 44 | 45 | 46 | ## Updating Dependencies 47 | 48 | Most dependencies are automatically checked for updates via [Dependabot](.github/dependabot.yml). 49 | 50 | The remaining dependencies cannot be managed via Dependabot, because they are manually retrieved 51 | during release via [0-get-latest-dependencies-versions.sh](./release/0-get-latest-dependencies-versions.sh). 52 | * Hence, a weekly GitHub Action [check-manual-dependencies](.github/workflows/check-manual-dependencies.yml) checks whether the committed [versions.txt](release/versions.txt) matches the actual latest versions. 53 | * If there is a new version, then the build creates a pull request with the new versions and the CI automatically runs it. 54 | * The pull request is [automatically merged](https://github.com/peter-evans/enable-pull-request-automerge), when the CI tests pass. 55 | * We need to use a [SSH deploy key](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#push-using-ssh-deploy-keys), as otherwise the automatic CI tests wouldn't be triggered. We created a secret `NEW_PULL_REQUEST_KEY` and it's corresponding deploy key for that. 56 | * For the pull request to be auto-merged, we need to have a branch protection rule. 57 | We [created one](https://github.com/qaware/protocurl/settings/branches) where the `test` workflow must pass as a status check before a pull request can be merged. 58 | -------------------------------------------------------------------------------- /dev/.gitignore: -------------------------------------------------------------------------------- 1 | generated.local.Dockerfile 2 | -------------------------------------------------------------------------------- /dev/builder.local.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12-slim AS builder 2 | # A developer variant of protocurl for local development. See DEVELOPER.md 3 | # This should be kept in sync with release/builder.Dockerfile 4 | 5 | ARG PROTO_VERSION 6 | ARG ARCH 7 | ARG GO_DOWNLOAD_URL_ARCH_TEMPLATE 8 | 9 | RUN apt-get -q update && apt-get -q install -y git curl 10 | COPY release/20-install-go.sh /install-go.sh 11 | RUN export URL="$(echo $GO_DOWNLOAD_URL_ARCH_TEMPLATE | sed "s/__ARCH__/$ARCH/g")"; /install-go.sh "$URL" this-is-not-my-development-computer 12 | 13 | WORKDIR /protocurl 14 | COPY release/tmp/protoc-$PROTO_VERSION-linux-$ARCH/bin/protoc /protocurl/protocurl-internal/bin/protoc 15 | COPY release/tmp/protoc-$PROTO_VERSION-linux-$ARCH/include/ /protocurl/protocurl-internal/include/ 16 | COPY src/*go* /protocurl/ 17 | 18 | RUN go get -d ./... 19 | RUN go build -v -ldflags="-X 'main.version=' -X 'main.commit='" -o bin/protocurl 20 | RUN rm -rf *go* 21 | -------------------------------------------------------------------------------- /dev/generate-local.Dockerfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Concatenate the dev dockerfile and the final release dockerfile to get the combined one 5 | cat dev/builder.local.Dockerfile <(echo "# ==================") release/final.Dockerfile >dev/generated.local.Dockerfile 6 | -------------------------------------------------------------------------------- /doc/generated.usage.txt: -------------------------------------------------------------------------------- 1 | protocurl , build , https://github.com/qaware/protocurl 2 | 3 | protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats. 4 | 5 | Usage: 6 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 7 | 8 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 9 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 10 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 11 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 12 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 13 | When converting between binary and text, the encoding UTF-8 is always used. 14 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 15 | 16 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 17 | 18 | Examples: 19 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 20 | 21 | Flags: 22 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 23 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 24 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 25 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 26 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 27 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 28 | -h, --help help for protocurl 29 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 30 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 31 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 32 | --no-curl Forces the use of the built-in internal http request instead of curl. 33 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 34 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 35 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 36 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 37 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 38 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 39 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 40 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 41 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 42 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 43 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 44 | -u, --url string Mandatory: The url to send the request to 45 | -v, --verbose Prints version and enables verbose output. Also activates -D. 46 | --version version for protocurl 47 | -------------------------------------------------------------------------------- /doc/template.EXAMPLES.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Examples 12 | 13 | After starting the local test server via `source test/suite/setup.sh && startServer`, you can send 14 | the following list of requests via protoCURL. The [test/proto/happyday.proto](test/proto/happyday.proto) is used for these examples. 15 | 16 | Each request needs to mount the directory of proto files into the containers `/proto` path to ensure, that they are 17 | visible inside the docker container. 18 | 19 | All of these commands work with the native CLI as well as docker. For the native CLI, one can simply use `protocurl -I $PWD/test/proto` instead of `docker run -v $PWD/test/proto:/proto --network host protocurl` 20 | 21 | **Basic Example** 22 | 23 | ```bash 24 | ___EXAMPLE_1___ 25 | ``` 26 | 27 | **Explict full message package paths and explicit proto file** 28 | 29 | ```bash 30 | ___EXAMPLE_2___ 31 | ``` 32 | 33 | **Using imported and nested messages such as well-known Google Protobuf types** 34 | 35 | ```bash 36 | ___EXAMPLE_3___ 37 | ``` 38 | 39 | **Omitting -o \ shows raw format** 40 | 41 | ```bash 42 | ___EXAMPLE_RAW_FORMAT__ 43 | ``` 44 | 45 | When the response type is unknown or one wants to debug and see what is all in the response, 46 | then this format shows the values for the given field numbers (instead of their field names). 47 | 48 | However, since 49 | [Protobuf is not self-describing](https://protobuf.dev/programming-guides/techniques/#self-description) 50 | the types cannot be correctly inferred and may be incorrect. 51 | 52 | **JSON** 53 | 54 | If your input text starts with a `{`, then it is inferred to be JSON 55 | and the output will automatically be shown in JSON format. 56 | 57 | ```bash 58 | ___EXAMPLE_JSON___ 59 | ``` 60 | 61 | **JSON with pretty-printing** 62 | 63 | ```bash 64 | ___EXAMPLE_JSON_PRETTY___ 65 | ``` 66 | 67 | **Show response output only via -q** 68 | 69 | ```bash 70 | ___EXAMPLE_OUTPUT_ONLY___ 71 | ``` 72 | 73 | With `-q` all errors are written to stderr making it ideal for piping in scripts. Hence this request against a non-existing endpoint 74 | 75 | ```bash 76 | ___EXAMPLE_OUTPUT_ONLY_WITH_ERR_1___ 77 | ``` 78 | 79 | will produce no output, exit with a non-zero exitcode and only show this error: 80 | 81 | ```bash 82 | ___EXAMPLE_OUTPUT_ONLY_WITH_ERR_2___ 83 | ``` 84 | 85 | **No Default Header** 86 | 87 | Some headers use default values (e.g. `Content-Type: application/x-protobuf`). If you do not want to use these default values, use `--no-default-headers` flag (only work when using `--curl`). 88 | 89 | ```bash 90 | ___EXAMPLE_NO_DEFAULT_HEADER___ 91 | ``` 92 | 93 | 94 | **Verbose via -v** 95 | 96 | ```bash 97 | ___EXAMPLE_4___ 98 | ``` 99 | -------------------------------------------------------------------------------- /release/.cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /release/.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | generated.Dockerfile 3 | new.versions.txt 4 | -------------------------------------------------------------------------------- /release/0-get-latest-dependencies-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | LATEST_VERSION="" 5 | 6 | HEADERS_FILE="release/.cache/headers.txt" 7 | 8 | # track all versions, so that we can detect any changes. 9 | export ALL_VERSIONS="" 10 | 11 | registerVersion() { 12 | NAME="$1" 13 | VERSION_VAR="$2" 14 | VERSION_VALUE="${!VERSION_VAR}" 15 | 16 | ALL_VERSIONS="$ALL_VERSIONS"$'\n'"$NAME $VERSION_VALUE" 17 | 18 | echo "Established $NAME version $VERSION_VALUE" 19 | } 20 | 21 | retrieveLatestVersion() { 22 | TYPE="$1" # tag or release 23 | REPO="$2" 24 | TAG_FILTER="$3" 25 | 26 | FILE_FRIENDLY_NAME="$(echo "$REPO" | sed 's#/#.#g')" 27 | 28 | CACHE_FILE="release/.cache/$FILE_FRIENDLY_NAME.cache.json" 29 | ETAG_FILE="release/.cache/$FILE_FRIENDLY_NAME.etag" 30 | ETAG="$(cat "$ETAG_FILE" 2>/dev/null || echo '')" 31 | 32 | if [[ "$TYPE" == "release" ]]; then 33 | ENDPOINT="releases?per_page=20" 34 | RESPONSE_FILTER="^$TAG_FILTER\$" 35 | PATH_TO_TAG=".tag_name" 36 | LATEST_VERSION_EXTRACTOR="head" 37 | else 38 | # Actually, we should only be getting the first 100 tags. 39 | # However, currently github returns all tags. 40 | # See issue: https://github.com/github/docs/issues/3863 41 | ENDPOINT="git/matching-refs/tags?per_page=100" 42 | RESPONSE_FILTER="^refs/tags/$TAG_FILTER\$" 43 | PATH_TO_TAG=".ref" 44 | LATEST_VERSION_EXTRACTOR="tail" 45 | fi 46 | 47 | AUTH_ARG="" 48 | if [[ -v GITHUB_TOKEN ]]; then 49 | AUTH_ARG="-H 'Authorization: Bearer $GITHUB_TOKEN'" 50 | fi 51 | 52 | GITHUB_RESPONSE="$(curl -s \ 53 | -D "$HEADERS_FILE" \ 54 | --etag-save "$ETAG_FILE" \ 55 | -H "If-None-Match: $ETAG" \ 56 | -H "Accept: application/vnd.github.v3+json" \ 57 | $AUTH_ARG \ 58 | "https://api.github.com/repos/$REPO/$ENDPOINT")" 59 | 60 | STATUS_CODE_LINE="$(cat "$HEADERS_FILE" | head -n 1)" 61 | 62 | if [[ "$STATUS_CODE_LINE" == *" 200"* ]]; then 63 | echo "Populating cache..." 64 | echo "$GITHUB_RESPONSE" >"$CACHE_FILE" 65 | fi 66 | 67 | if [[ "$STATUS_CODE_LINE" == *" 304"* ]]; then 68 | echo "Using cache..." 69 | GITHUB_RESPONSE="$(cat "$CACHE_FILE")" 70 | fi 71 | 72 | FILTERED_TAGS="$(echo "$GITHUB_RESPONSE" | jq -r ".[] | select($PATH_TO_TAG | test(\"$RESPONSE_FILTER\")) | $PATH_TO_TAG")" 73 | 74 | LATEST_VERSION="$(echo "$FILTERED_TAGS" | $LATEST_VERSION_EXTRACTOR -n 1)" 75 | 76 | if [[ ! -v LATEST_VERSION ]]; then 77 | echo "Found tags after filtering:" 78 | echo "$FILTERED_TAGS" 79 | echo "Error: Could not find latest $TYPE for github.com/$REPO with filter $TAG_FILTER" 80 | echo "Result: $LATEST_VERSION" 81 | exit 1 82 | fi 83 | 84 | LATEST_VERSION="${LATEST_VERSION#"refs/tags/"}" 85 | } 86 | 87 | # retrieve version: Google Protobuf 88 | retrieveLatestVersion "tag" "protocolbuffers/protobuf" "v[0-9]+[.][0-9]+" 89 | export PROTO_VERSION="${LATEST_VERSION#"v"}" 90 | registerVersion "Protobuf" "PROTO_VERSION" 91 | 92 | # retrieve version: go 93 | retrieveLatestVersion "tag" "golang/go" "go1[.][0-9]+[.][0-9]+" 94 | GO_VERSION="${LATEST_VERSION#"go"}" 95 | # GO_VERSION="$(echo "$GO_VERSION" | sed -E "s/\.[0-9]+$//")" # remove patch version 96 | registerVersion "go" "GO_VERSION" 97 | 98 | # retrieve version: goreleaser 99 | retrieveLatestVersion "tag" "goreleaser/goreleaser" "v1[.][0-9]+[.][0-9]+" 100 | export GORELEASER_VERSION="$LATEST_VERSION" 101 | registerVersion "Goreleaser" "GORELEASER_VERSION" 102 | 103 | # retrieve version: protocurl 104 | retrieveLatestVersion "tag" "qaware/protocurl" "v[0-9]+[.][0-9]+[.][0-9]+" 105 | export PROTOCURL_RELEASED_VVERSION="$LATEST_VERSION" 106 | registerVersion "Latest released protoCURL" "PROTOCURL_RELEASED_VVERSION" 107 | 108 | # compute download urls 109 | ARCH="$(uname -m | sed "s/x86_64/amd64/" | sed "s/x86_32/386/")" 110 | 111 | export GO_DOWNLOAD_URL="https://go.dev/dl/go${GO_VERSION}.linux-$ARCH.tar.gz" 112 | export GO_DOWNLOAD_URL_ARCH_TEMPLATE="https://go.dev/dl/go${GO_VERSION}.linux-__ARCH__.tar.gz" # used in Dockerfile 113 | 114 | export GORELEASER_DOWNLOAD_URL="https://github.com/goreleaser/goreleaser/releases/download/${GORELEASER_VERSION}/goreleaser_${GORELEASER_VERSION#"v"}_${ARCH}.deb" 115 | -------------------------------------------------------------------------------- /release/10-ensure-protoc-binaries-exist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | source ./release/0-get-latest-dependencies-versions.sh 5 | 6 | FILES_EXIST="true" 7 | ls release/tmp/protoc-$PROTO_VERSION-*.zip > /dev/null 2>&1 || FILES_EXIST="false" 8 | 9 | if [[ "$FILES_EXIST" == "true" ]]; then 10 | echo "Found protoc binaries for $PROTO_VERSION." 11 | else 12 | echo "No protoc binaries for $PROTO_VERSION found. Downloading..." 13 | ./release/10.1-get-protoc-binaries.sh 14 | fi 15 | -------------------------------------------------------------------------------- /release/10.1-get-protoc-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # platforms and architectures for which Google released pre-built binaries 5 | VARIATIONS=( 6 | "linux-aarch_64" 7 | "linux-x86_32" 8 | "linux-x86_64" 9 | "osx-aarch_64" 10 | "osx-x86_64" 11 | "win32" 12 | "win64" 13 | ) 14 | 15 | rm -rf release/tmp || true 16 | mkdir -p release/tmp 17 | 18 | for PLAT_ARCH in "${VARIATIONS[@]}"; do 19 | URL="https://github.com/protocolbuffers/protobuf/releases/download/v$PROTO_VERSION/protoc-$PROTO_VERSION-$PLAT_ARCH.zip" 20 | 21 | echo "Downloading $URL ..." 22 | curl -s -L -o "release/tmp/protoc-$PROTO_VERSION-$PLAT_ARCH.zip" "$URL" 23 | 24 | # Normalise platform name for integration into Goreleaser and docker 25 | NORM_PLAT_ARCH="$(echo "$PLAT_ARCH" | 26 | sed "s/win32/windows-386/" | 27 | sed "s/win64/windows-amd64/" | 28 | sed "s/osx/darwin/" | 29 | sed "s/x86_64/amd64/" | 30 | sed "s/x86_32/386/" | 31 | sed "s/aarch_64/arm64/")" 32 | 33 | echo "Extracting $PROTO_VERSION-$PLAT_ARCH to $PROTO_VERSION-$NORM_PLAT_ARCH" 34 | unzip -q -d "release/tmp/protoc-$PROTO_VERSION-$NORM_PLAT_ARCH" "release/tmp/protoc-$PROTO_VERSION-$PLAT_ARCH.zip" 35 | done 36 | 37 | echo "Done." 38 | -------------------------------------------------------------------------------- /release/100-check-latest-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | SAVED="release/versions.txt" 5 | NEW="release/new.versions.txt" 6 | 7 | echo "Checking $SAVED against latest versions..." 8 | 9 | # Ths scripts checks the latest versions of the dependencies against what is checked in at versions.log. 10 | # See RELEASE.md 11 | 12 | OUT="$NEW" ./release/101-save-latest-versions.sh 13 | 14 | if diff "$SAVED" "$NEW"; then 15 | echo "✅ No new dependency versions." 16 | else 17 | echo "❗❗ New dependency versions found ❗❗" 18 | # diff is automatically printed in the if statement 19 | echo "Please do the following: 20 | 1. Run ./release/101-save-latest-versions.sh 21 | 2. Commit new versions 22 | 3. Create a new release" 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /release/101-save-latest-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # See RELEASE.md 5 | 6 | source release/0-get-latest-dependencies-versions.sh 7 | 8 | OUT="${OUT:-"release/versions.txt"}" 9 | 10 | # ignore empty lines. ignore protoCURL itself. 11 | echo "$ALL_VERSIONS" | sed '/^$/d' | sed '/protoCURL/d' >"$OUT" 12 | 13 | echo "Saved latest versions into $OUT." 14 | -------------------------------------------------------------------------------- /release/20-install-go.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | set -x 4 | 5 | # Installs Go inside a GitHub action VM / Docker container environment 6 | 7 | # avoid anyone accidentally running this on their development computer 8 | if [[ "$2" == "this-is-not-my-development-computer" ]]; then 9 | 10 | URL="$1" 11 | 12 | echo "Installing go from $URL" 13 | 14 | curl -s -L -o go.tar.gz "$URL" 15 | 16 | rm -rf /usr/local/go 17 | 18 | tar -C /usr/local -xzf go.tar.gz 19 | 20 | ln -s /usr/local/go/bin/go /usr/local/bin/go 21 | 22 | echo "Done." 23 | 24 | else 25 | echo "This should only be run inside a docker container / Dockerfile build process as it will overwrite your exisitng global go installation." 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /release/30-build-go-archive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | source release/source.sh 5 | 6 | cp template.goreleaser.yaml .goreleaser.yaml 7 | sed -i "s/__PROTO_VERSION__/$PROTO_VERSION/g" .goreleaser.yaml 8 | 9 | set -x 10 | 11 | goreleaser check 12 | 13 | echo "Using GORELEASER_CURRENT_TAG=$GORELEASER_CURRENT_TAG, GORELEASER_PREVIOUS_TAG=$GORELEASER_PREVIOUS_TAG" 14 | 15 | GORELEASER_ARGS="" 16 | if [[ "$SNAPSHOT" == "true" ]]; then 17 | GORELEASER_ARGS="--skip-announce" 18 | fi 19 | 20 | goreleaser release --clean $GORELEASER_ARGS 21 | 22 | # Alternate commands when testing release process locally 23 | # goreleaser release --snapshot --clean # DEV 24 | # set -x; for file in dist/*.zip; do mv "$file" "${file/-next/}"; done # DEV 25 | 26 | set +x 27 | -------------------------------------------------------------------------------- /release/40-generate-Dockerfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | cat release/builder.Dockerfile <(echo "# ==================") release/final.Dockerfile >release/generated.Dockerfile 4 | -------------------------------------------------------------------------------- /release/builder.Dockerfile: -------------------------------------------------------------------------------- 1 | # This should be kept in sync with dev/builder.local.Dockerfile 2 | 3 | FROM debian:12-slim AS builder 4 | ARG VERSION 5 | ARG TARGETARCH 6 | RUN apt-get -q update && \ 7 | apt-get -q install -y curl unzip zlib1g 8 | WORKDIR /protocurl 9 | COPY dist/protocurl_${VERSION}_linux_${TARGETARCH}.zip ./ 10 | RUN unzip *.zip && rm -f *.md *.zip && ls -lh . && apt-get -q purge -y unzip 11 | COPY LICENSE.md README.md ./ 12 | -------------------------------------------------------------------------------- /release/final.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/distroless/cc:latest AS final 2 | 3 | WORKDIR /protocurl 4 | 5 | COPY --from=builder /usr/bin/curl /usr/bin/curl 6 | 7 | # Ideally, we would simply copy these lib files based on their architecture. Unfortunately, we cannot use 8 | # a build arg such as "ARG ARCH_UNAME_M" here with format as given by "uname -m" (x86_64, etc.). 9 | # However, the buildx build command for multi-architecture images only provides TARGETARCH which 10 | # uses go style (amd64, amd32, arm64, etc.). However, we actually want a COPY statement of the form 11 | # COPY --from=builder /lib/$ARCH_UNAME_M-linux-gnu /lib/$ARCH_UNAME_M-linux-gnu 12 | # - which cannot be done with the TARGETARCH build arg. Since the build-arg is set by the enclosing 13 | # buildx command, we cannot intercept it or make our mapping before hand. 14 | # We also cannot first copy to "/lib/amd64-linux-gnu" etc. and then rename the folder, 15 | # because we don't have the linux command "mv" as we are in a distroless context. 16 | # Even if we temporarily copy "mv" from the builder image - it would not work, as it will require 17 | # libraries from /lib/$ARCH_UNAME_M-linux-gnu to run... But these are what we are trying to fix and move in the first place! 18 | # My head exploded. 19 | # Hence, my hack: I decided just to duplicate the folder for each architecture. 20 | # The docker image will be uncessarily large... but one could simply use 21 | # the native CLI for better speed and smaller download size anyways. 22 | 23 | # We only support 64-bit docker images 24 | COPY --from=builder /usr/lib/*-linux-gnu /usr/lib/x86_64-linux-gnu/ 25 | COPY --from=builder /usr/lib/*-linux-gnu /usr/lib/aarch_64-linux-gnu/ 26 | 27 | COPY --from=builder /lib/*-linux-gnu /lib/x86_64-linux-gnu/ 28 | COPY --from=builder /lib/*-linux-gnu /lib/aarch_64-linux-gnu/ 29 | 30 | COPY --from=builder /lib64*/ld-linux-*.so.2 /lib64/ 31 | 32 | COPY --from=builder /protocurl/ /protocurl/ 33 | ENTRYPOINT ["/protocurl/bin/protocurl"] 34 | -------------------------------------------------------------------------------- /release/source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # PRECONDITION: git fetch origin --tags 5 | 6 | source ./release/10-ensure-protoc-binaries-exist.sh 7 | 8 | # should be one of 386, amd64 and arm64 9 | export BUILD_ARCH="$(uname -m | sed "s/x86_64/amd64/" | sed "s/x86_32/386/" | sed "s/aarch_64/arm64/")" 10 | 11 | # ensure, that 1.2.3-rc < 1.2.3, since the opposite is the default 12 | git config versionsort.suffix - 13 | # See: https://github.com/git/git/blob/master/Documentation/config/versionsort.txt 14 | 15 | if [[ ! -v VVERSION ]]; then 16 | 17 | GIT_TAG="$(git tag --points-at HEAD --sort -version:refname | head -n 1)" 18 | if [[ "$GIT_TAG" != "" ]]; then 19 | export VVERSION="$GIT_TAG" 20 | else 21 | LATEST_TAG="$(git for-each-ref --sort='-version:refname' --count 1 --format '%(refname:short)' refs/tags)" 22 | export VVERSION="$LATEST_TAG-dev" 23 | fi 24 | fi 25 | 26 | # any version: e.g. v1.2.3, v23.45.67-dev 27 | if [[ "$VVERSION" =~ v.*\..*\..* ]]; then 28 | 29 | # any snapshot version with a - 30 | # e.g. v23.45.67-dev but not v1.2.3 31 | if [[ "$VVERSION" =~ v.*\..*\..*[-].* ]]; then 32 | export SNAPSHOT="true" 33 | else 34 | export SNAPSHOT="false" 35 | fi 36 | 37 | export VERSION="${VVERSION#"v"}" 38 | echo "Variables: VERSION=$VERSION, VVERSION=$VVERSION, SNAPSHOT=$SNAPSHOT, BUILD_ARCH=$BUILD_ARCH, PROTO_VERSION=$PROTO_VERSION" 39 | else 40 | echo "Closest git tag is not a version tag: $VVERSION" 41 | echo "Could not extract current version from git tags. Please tag accordingly. Or provide one manually" 42 | exit 1 43 | fi 44 | -------------------------------------------------------------------------------- /release/versions.txt: -------------------------------------------------------------------------------- 1 | Protobuf 31.1 2 | go 1.24.3 3 | Goreleaser v1.26.2 4 | -------------------------------------------------------------------------------- /src/bundled.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // We're always using path/filepath instead of path for OS-aware path operations 11 | 12 | const ProtocurlInternalName = "protocurl-internal" 13 | 14 | func getProtocurlInternalPath() (string, error) { 15 | protocurlPath, err := os.Executable() 16 | if err != nil { 17 | return "", err 18 | } 19 | protocurlPath, err = normaliseFilePath(protocurlPath) 20 | if err != nil { 21 | return "", err 22 | } 23 | 24 | internalPathErrorMsg := "Cannot find '" + ProtocurlInternalName + "' directory.\n" + 25 | "Please ensure that you correctly extracted the full protocurl archive.\n" + 26 | "I was expecting to find a directory '" + ProtocurlInternalName + "' side by side\n" + 27 | "to the bin directory containing the protocurl executable.\n" + 28 | "The executable was found at " + protocurlPath + "\n" + 29 | "Error: " 30 | 31 | // /path/to/pc/bin/protocurl[ext] -> /path/to/pc/protocurl-internal 32 | unnormalisedProtocurlInternalPath := filepath.Join(filepath.Dir(filepath.Dir(protocurlPath)), ProtocurlInternalName) 33 | protocurlInternalPath, err := normaliseFilePath(unnormalisedProtocurlInternalPath) 34 | if err != nil { 35 | return "", errors.New(internalPathErrorMsg + err.Error()) 36 | } 37 | 38 | if _, err := os.Stat(protocurlInternalPath); !os.IsNotExist(err) { 39 | return protocurlInternalPath, nil 40 | } else { 41 | return "", errors.New(internalPathErrorMsg + err.Error()) 42 | } 43 | } 44 | 45 | func getGoogleProtobufIncludePath(useBundled bool) string { 46 | var includePath string 47 | 48 | if useBundled { 49 | protocurlInternalPath, err := getProtocurlInternalPath() 50 | PanicOnError(err) 51 | includePath = filepath.Join(protocurlInternalPath, "include") 52 | } else { 53 | includePath = GlobalGoogleProtobufIncludePath 54 | } 55 | 56 | if CurrentConfig.Verbose { 57 | fmt.Printf("Using google protobuf include: %s\n", includePath) 58 | } 59 | 60 | return includePath 61 | } 62 | -------------------------------------------------------------------------------- /src/errorHandling.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "os" 8 | ) 9 | 10 | // AssertSuccess Use, when error indicates bug in code. Otherwise, use the other functions 11 | func AssertSuccess(err error) { 12 | if err != nil { 13 | log.Panic(err) 14 | } 15 | } 16 | 17 | func PrintError(err error) { 18 | if err != nil { 19 | _, _ = fmt.Fprintln(os.Stderr, "Error: "+err.Error()) 20 | } 21 | } 22 | 23 | func PanicOnError(err error) { 24 | if err != nil { 25 | panic(interface{}(err)) 26 | } 27 | } 28 | 29 | func PanicWithMessage(message string) { 30 | panic(interface{}(errors.New(message))) 31 | } 32 | 33 | func PanicWithMessageOnError(err error, lazyMessage func() string) { 34 | if err != nil { 35 | panic(interface{}(lazyMessage() + "\nUnderlying error: " + err.Error())) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/executables.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "runtime" 10 | "strings" 11 | ) 12 | 13 | // We're always using path/filepath instead of path for OS-aware path operations 14 | 15 | const ProtocExecutableName = "protoc" // You may want to wrap it within osAwareExecutableName 16 | const CurlExecutableName = "curl" // You may want to wrap it within osAwareExecutableName 17 | 18 | const GlobalGoogleProtobufIncludePath = "/usr/bin/include" 19 | 20 | var extensions = map[string]string{"windows": ".exe"} 21 | var currentOsExt = (extensions)[runtime.GOOS] 22 | 23 | var foundExecutables = make(map[string]string) 24 | 25 | func findProtocExecutable() (string, bool /* true, if bundled protoc is used */) { 26 | if !CurrentConfig.GlobalProtoc { 27 | protocPath, err := getInternalProtocExec() 28 | PanicOnError(err) 29 | return protocPath, true 30 | } else { 31 | if CurrentConfig.Verbose { 32 | fmt.Printf("GlobalProtoc is set, hence bundled protoc will be ignored.\n") 33 | } 34 | } 35 | protocPath, _ := getExecutablePathOrLookup(CurrentConfig.CustomProtocPath, ProtocExecutableName, true) 36 | return protocPath, false 37 | } 38 | 39 | func findCurlExecutable(force bool) (string, error) { 40 | return getExecutablePathOrLookup(CurrentConfig.CustomCurlPath, CurlExecutableName, force) 41 | } 42 | 43 | func getExecutablePathOrLookup(optionalExecPath string, name string, force bool) (string, error) { 44 | if optionalExecPath != "" { 45 | execPathWithExt := osAwareExecutableName(optionalExecPath) 46 | if CurrentConfig.Verbose { 47 | fmt.Printf("Using custom "+name+" path: %s\n", optionalExecPath) 48 | } 49 | return execPathWithExt, nil 50 | } else { 51 | return findExecutable(osAwareExecutableName(name), force) 52 | } 53 | } 54 | 55 | //goland:noinspection GoBoolExpressions 56 | func osAwareExecutableName(path string) string { 57 | if runtime.GOOS == "windows" && !strings.HasSuffix(path, currentOsExt) { 58 | var newPath = path + currentOsExt 59 | if CurrentConfig.Verbose { 60 | fmt.Printf("Path after os extension (%s): %s\n", currentOsExt, newPath) 61 | } 62 | return newPath 63 | } 64 | return path 65 | } 66 | 67 | // Returns the filesystem path for the executable of the given name in the env PATH. 68 | // If force is set, then failure to find the executable will panic. Otherwise, only an error will be returned. 69 | func findExecutable(name string, force bool) (string, error) { 70 | if foundExecutables[name] != "" { 71 | return foundExecutables[name], nil 72 | } 73 | 74 | executable, err := exec.LookPath(name) 75 | if err != nil { 76 | if force { 77 | PanicWithMessageOnError(err, func() string { return "I could not find a '" + name + "' executable. Please check your PATH." }) 78 | } else { 79 | if CurrentConfig.Verbose { 80 | fmt.Printf("Did not find executable %s.\n", name) 81 | } 82 | return "", err 83 | } 84 | } 85 | 86 | foundExecutables[name] = executable 87 | 88 | if CurrentConfig.Verbose { 89 | fmt.Printf("Found %s: %s\n", name, executable) 90 | } 91 | return executable, nil 92 | } 93 | 94 | func getInternalProtocExec() (string, error) { 95 | protocName := osAwareExecutableName(ProtocExecutableName) 96 | protocurlInternalPath, err := getProtocurlInternalPath() 97 | if err != nil { 98 | return "", err 99 | } 100 | protocInternalPath := filepath.Join(protocurlInternalPath, "bin", protocName) 101 | 102 | _, err = os.Stat(protocInternalPath) 103 | if os.IsNotExist(err) { 104 | return "", errors.New("Could not find bundled executable " + protocName + " \nError: " + err.Error()) 105 | } else if err != nil { 106 | return "", err 107 | } 108 | 109 | if CurrentConfig.Verbose { 110 | fmt.Printf("Found bundled protoc at %s\n", protocInternalPath) 111 | } 112 | 113 | return protocInternalPath, nil 114 | } 115 | 116 | func normaliseFilePath(filePath string) (string, error) { 117 | filePath, err := filepath.Abs(filePath) 118 | if err != nil { 119 | return "", err 120 | } 121 | filePath, err = filepath.EvalSymlinks(filePath) 122 | if err != nil { 123 | return "", err 124 | } 125 | filePath, err = filepath.Abs(filePath) 126 | if err != nil { 127 | return "", err 128 | } 129 | return filePath, nil 130 | } 131 | -------------------------------------------------------------------------------- /src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/qaware/protocurl/src 2 | 3 | go 1.22 4 | 5 | toolchain go1.24.1 6 | 7 | require ( 8 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 9 | github.com/spf13/cobra v1.9.1 10 | google.golang.org/protobuf v1.36.6 11 | ) 12 | 13 | require ( 14 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 15 | github.com/spf13/pflag v1.0.6 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /src/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 2 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 3 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 5 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 6 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 7 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 8 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 9 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= 10 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= 11 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 12 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 13 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 14 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 15 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 16 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 17 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 18 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 19 | -------------------------------------------------------------------------------- /src/httpRequest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "net/http" 10 | "net/http/httputil" 11 | "os" 12 | "os/exec" 13 | "path/filepath" 14 | "regexp" 15 | "strings" 16 | 17 | "github.com/kballard/go-shellquote" 18 | ) 19 | 20 | const publicReadPermissions os.FileMode = 0644 21 | 22 | func invokeInternalHttpRequest(requestBinary []byte) ([]byte, string) { 23 | if CurrentConfig.Verbose { 24 | fmt.Println("Invoking internal http request.") 25 | } 26 | 27 | if usingUnsupportedNonDefaultHeaders() { 28 | PanicDueToUnsupportedHeadersWhenInternalHttp(CurrentConfig.RequestHeaders) 29 | } 30 | 31 | var httpResponse *http.Response 32 | var err error 33 | switch CurrentConfig.Method { 34 | case "GET": 35 | if CurrentConfig.RequestType != "" { 36 | PanicWithMessage("Internal Http implementation doesn't support GET requests with body. Please use curl.") 37 | } 38 | httpResponse, err = http.Get(CurrentConfig.Url) 39 | case "POST": 40 | httpResponse, err = http.Post(CurrentConfig.Url, DefaultContentType, bytes.NewReader(requestBinary)) 41 | default: 42 | PanicWithMessage("HTTP method " + CurrentConfig.Method + " not supported with internal HTTP implementation. Please use curl.") 43 | } 44 | 45 | PanicWithMessageOnError(err, func() string { return "Failed internal HTTP request. Error: " + err.Error() }) 46 | defer func() { _ = httpResponse.Body.Close() }() 47 | 48 | body, err := io.ReadAll(httpResponse.Body) 49 | PanicOnError(err) 50 | 51 | headers, err := httputil.DumpResponse(httpResponse, false) 52 | headersString := string(headers) 53 | 54 | ensureStatusCodeIs2XX(headersString) 55 | 56 | return body, strings.TrimSpace(headersString) 57 | } 58 | 59 | func usingUnsupportedNonDefaultHeaders() bool { 60 | usingNonDefaultHeaders := len(CurrentConfig.RequestHeaders) != 1 || CurrentConfig.RequestHeaders[0] != DefaultHeaders[0] 61 | return CurrentConfig.NoDefaultHeaders || usingNonDefaultHeaders 62 | } 63 | 64 | func invokeCurlRequest(requestBinary []byte, curlPath string) ([]byte, string) { 65 | if CurrentConfig.Verbose { 66 | fmt.Println("Invoking curl http request.") 67 | } 68 | 69 | tmpDir, err := os.MkdirTemp(os.TempDir(), "protocurl-temp-*") 70 | PanicOnError(err) 71 | defer func() { _ = os.RemoveAll(tmpDir) }() 72 | 73 | requestBinaryFile := filepath.Join(tmpDir, "request.bin") 74 | err = os.WriteFile(requestBinaryFile, requestBinary, publicReadPermissions) 75 | PanicOnError(err) 76 | 77 | responseBinaryFile := filepath.Join(tmpDir, "response.bin") 78 | responseHeadersTextFile := filepath.Join(tmpDir, "response-headers.txt") 79 | 80 | curlArgs := []string{ 81 | curlPath, 82 | "-s", 83 | "-X", CurrentConfig.Method, 84 | "--output", responseBinaryFile, 85 | "--dump-header", responseHeadersTextFile, 86 | } 87 | 88 | if CurrentConfig.RequestType != "" { 89 | curlArgs = append(curlArgs, "--data-binary", "@"+requestBinaryFile) 90 | } 91 | 92 | for _, header := range CurrentConfig.RequestHeaders { 93 | curlArgs = append(curlArgs, "-H", header) 94 | } 95 | 96 | individualAdditionalCurlArgs, err := shellquote.Split(CurrentConfig.AdditionalCurlArgs) 97 | PanicOnError(err) 98 | if CurrentConfig.Verbose { 99 | fmt.Printf("Understood additional curl args: %+q\n", individualAdditionalCurlArgs) 100 | } 101 | curlArgs = append(curlArgs, individualAdditionalCurlArgs...) 102 | 103 | curlArgs = append(curlArgs, CurrentConfig.Url) 104 | 105 | if CurrentConfig.Verbose { 106 | fmt.Printf("Total curl args:\n %s\n", strings.Join(curlArgs[1:], "\n ")) 107 | } 108 | 109 | curlStdOut := bytes.NewBuffer([]byte{}) 110 | curlStdErr := bytes.NewBuffer([]byte{}) 111 | curlCmd := exec.Cmd{ 112 | Path: curlPath, 113 | Args: curlArgs, 114 | Stdout: bufio.NewWriter(curlStdOut), 115 | Stderr: bufio.NewWriter(curlStdErr), 116 | } 117 | 118 | err = curlCmd.Run() 119 | 120 | if !CurrentConfig.ShowOutputOnly && !CurrentConfig.SilentMode && curlStdOut.Len() != 0 { 121 | fmt.Printf("%s CURL Output %s\n%s\n", VISUAL_SEPARATOR, VISUAL_SEPARATOR, curlStdOut.String()) 122 | } 123 | 124 | if !CurrentConfig.ShowOutputOnly && curlStdErr.Len() != 0 { 125 | fmt.Printf("%s CURL ERROR %s\n%s\n", VISUAL_SEPARATOR, VISUAL_SEPARATOR, curlStdErr.String()) 126 | } 127 | 128 | PanicWithMessageOnError(err, func() string { return "Encountered an error while running curl. Error: " + err.Error() }) 129 | 130 | responseBinary, err := os.ReadFile(responseBinaryFile) 131 | responseHeaders, err := os.ReadFile(responseHeadersTextFile) 132 | responseHeadersText := strings.TrimSpace(string(responseHeaders)) 133 | 134 | ensureStatusCodeIs2XX(responseHeadersText) 135 | 136 | return responseBinary, responseHeadersText 137 | } 138 | 139 | func ensureStatusCodeIs2XX(headers string) { 140 | httpStatusLine := strings.Split(headers, "\n")[0] 141 | matches, err := regexp.MatchString("HTTP/.* 2[0-9][0-9] .*", httpStatusLine) 142 | AssertSuccess(err) 143 | 144 | if !matches { 145 | err := errors.New("Request was unsuccessful. Received response status code outside of 2XX. Got: " + httpStatusLine) 146 | PanicOnError(err) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/protoConversions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | 6 | "google.golang.org/protobuf/encoding/protojson" 7 | "google.golang.org/protobuf/encoding/prototext" 8 | "google.golang.org/protobuf/proto" 9 | "google.golang.org/protobuf/reflect/protoregistry" 10 | "google.golang.org/protobuf/types/dynamicpb" 11 | ) 12 | 13 | /* 14 | Given a *protoregistry.Files corresponding to the provided .proto files, we can 15 | resolve the protobuf message descriptor given its name and use dynamicpb.NewMessage 16 | to create a message of that message type without needing to generate go code at runtime. 17 | 18 | Given a message, simple converters in prototext can be used for the conversion between binary and text format. 19 | 20 | See: 21 | https://pkg.go.dev/google.golang.org/protobuf/encoding/prototext 22 | https://pkg.go.dev/google.golang.org/protobuf/types/dynamicpb 23 | https://pkg.go.dev/google.golang.org/protobuf/reflect/protoregistry 24 | 25 | */ 26 | 27 | var binaryMarshalOptions = proto.MarshalOptions{ 28 | Deterministic: true, // stabilises test output 29 | } 30 | 31 | var textFormatOptions = prototext.MarshalOptions{ 32 | Multiline: true, 33 | Indent: " ", 34 | } 35 | 36 | var jsonDenseformatOptions = protojson.MarshalOptions{ 37 | UseProtoNames: true, 38 | } 39 | 40 | var jsonPrettyformatOptions = protojson.MarshalOptions{ 41 | UseProtoNames: true, 42 | Multiline: true, 43 | Indent: " ", 44 | } 45 | 46 | func textToMsgAndBinary(messageType string, text string, registry *protoregistry.Files) ([]byte, *dynamicpb.Message) { 47 | messageDescriptor := resolveMessageByName(messageType, registry) 48 | msg := dynamicpb.NewMessage(*messageDescriptor) 49 | 50 | var err error 51 | switch CurrentConfig.InTextType { 52 | case IText: 53 | err = prototext.Unmarshal([]byte(text), msg) 54 | case IJson: 55 | err = protojson.Unmarshal([]byte(text), msg) 56 | } 57 | PanicOnError(err) 58 | 59 | binary, err := binaryMarshalOptions.Marshal(msg) 60 | PanicOnError(err) 61 | 62 | return binary, msg 63 | } 64 | 65 | func protoBinaryToMsgAndText(messageType string, binary []byte, outFormat OutTextType, registry *protoregistry.Files) (string, *dynamicpb.Message) { 66 | messageDescriptor := resolveMessageByName(messageType, registry) 67 | msg := dynamicpb.NewMessage(*messageDescriptor) 68 | 69 | err := proto.Unmarshal(binary, msg) 70 | PanicOnError(err) 71 | 72 | var textBytes = []byte{} 73 | switch outFormat { 74 | case OText: 75 | textBytes, err = formatUnknownFieldsIfApplicable(textFormatOptions).Marshal(msg) 76 | case OJsonDense: 77 | textBytes, err = jsonDenseformatOptions.Marshal(msg) 78 | case OJsonPretty: 79 | textBytes, err = jsonPrettyformatOptions.Marshal(msg) 80 | } 81 | PanicOnError(err) 82 | 83 | text := string(textBytes) 84 | text = strings.TrimSuffix(text, "\n") 85 | 86 | return text, msg 87 | } 88 | 89 | func formatUnknownFieldsIfApplicable(opts prototext.MarshalOptions) prototext.MarshalOptions { 90 | newOpts := opts // shallow copy 91 | newOpts.EmitUnknown = true 92 | return newOpts 93 | } 94 | -------------------------------------------------------------------------------- /src/stdout.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | const VISUAL_SEPARATOR = "===========================" 10 | const SEND = ">>>" 11 | const RECV = "<<<" 12 | 13 | func EnsureMessageDescriptorIsResolved(requestType string, err error) { 14 | PanicWithMessageOnError(err, func() string { 15 | return "I couldn't find any Protobuf message for the message package-path " + requestType + ".\n" + 16 | "Did you correctly -I (include) your proto files directory?\n" + 17 | "Did you correctly specify the full message package-path to your Protobuf message type?\n" + 18 | "Try again with -v (verbose)." 19 | }) 20 | } 21 | 22 | func printArgsVerbose() { 23 | if CurrentConfig.Verbose { 24 | fmt.Println("Invoked with following default & parsed arguments:") 25 | printAsJson(CurrentConfig) 26 | } 27 | } 28 | 29 | func printVersionInfoVerbose(cmd *cobra.Command) { 30 | if CurrentConfig.Verbose { 31 | fmt.Printf("protocurl %s\n", cmd.Version) 32 | } 33 | } 34 | 35 | func printAsJson(obj interface{}) { 36 | jsonBytes, err := json.MarshalIndent(obj, "", " ") 37 | PanicOnError(err) 38 | fmt.Println(string(jsonBytes)) 39 | } 40 | -------------------------------------------------------------------------------- /template.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # Documentation at https://goreleaser.com 2 | 3 | # This file is a template and expressions such as __PROTOC_VERSION__ are replaced 4 | # with environment variables such as $PROTOC_VERSION before usage. 5 | 6 | # https://goreleaser.com/customization/build/ 7 | builds: 8 | - binary: bin/protocurl 9 | dir: src 10 | env: 11 | - CGO_ENABLED=0 12 | goos: 13 | - linux 14 | - windows 15 | - darwin 16 | ignore: 17 | # This combination is not pre-built by Google Protobuf 18 | - goos: windows 19 | goarch: arm64 20 | 21 | 22 | # https://goreleaser.com/customization/archive/ 23 | archives: 24 | - format: zip 25 | files: 26 | # NOTE: These files are listed again in the packages below. Keep them synced! 27 | # binary is added implicitly 28 | - README.md 29 | - LICENSE.md 30 | # copy protoc binaries and their .proto files previously downloaded 31 | - src: 'release/tmp/protoc-__PROTO_VERSION__-{{ .Os }}-{{ .Arch }}/bin' 32 | dst: 'protocurl-internal/bin' 33 | strip_parent: true # avoids, that protoc is copied into protocurl-internal/bin/release/tmp/.../bin 34 | - src: 'release/tmp/protoc-__PROTO_VERSION__-{{ .Os }}-{{ .Arch }}/include/google/protobuf' 35 | dst: 'protocurl-internal/include/google/protobuf' 36 | strip_parent: true 37 | 38 | # Linux packages 39 | nfpms: 40 | - package_name: protocurl 41 | description: |- 42 | protoCURL is cURL for Protobuf: 43 | The command-line tool for interacting with Protobuf over 44 | HTTP REST endpoints using human-readable text formats. 45 | 46 | homepage: https://github.com/qaware/protocurl 47 | license: MIT 48 | maintainer: GollyTicker 49 | priority: extra 50 | 51 | formats: 52 | - apk 53 | - deb 54 | dependencies: 55 | - curl 56 | suggests: 57 | - curl 58 | 59 | overrides: 60 | # protoc is compiled against glibc whereas alpine uses musl. 61 | # See: https://stackoverflow.com/a/64447927 62 | apk: 63 | dependencies: 64 | - curl 65 | - gcompat 66 | 67 | # adds the ./bin/protocurl 68 | bindir: /opt/protocurl 69 | 70 | # GoReleaser will automatically add the binaries. 71 | contents: 72 | - src: /opt/protocurl/bin/protocurl 73 | dst: /usr/bin/protocurl 74 | type: "symlink" 75 | 76 | # NOTE: These files are listed again in the archives above. Keep them synced! 77 | # binary is added implicitly 78 | - src: README.md 79 | dst: /opt/protocurl/README.md 80 | - src: LICENSE.md 81 | dst: /opt/protocurl/LICENSE.md 82 | # copy protoc binaries and their .proto files previously downloaded 83 | - src: 'release/tmp/protoc-__PROTO_VERSION__-{{ .Os }}-{{ .Arch }}/bin' 84 | dst: '/opt/protocurl/protocurl-internal/bin' 85 | - src: 'release/tmp/protoc-__PROTO_VERSION__-{{ .Os }}-{{ .Arch }}/include/google/protobuf' 86 | dst: '/opt/protocurl/protocurl-internal/include/google/protobuf' 87 | 88 | release: 89 | # If set to auto, will mark the release as not ready for production 90 | # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 91 | prerelease: auto 92 | 93 | 94 | checksum: 95 | name_template: 'checksums.txt' 96 | 97 | snapshot: 98 | name_template: "{{ .Version }}-dev" 99 | 100 | changelog: 101 | sort: asc 102 | filters: 103 | exclude: 104 | - '^docs:' 105 | - '^test:' 106 | -------------------------------------------------------------------------------- /test/payloads/invalid.txt: -------------------------------------------------------------------------------- 1 | includeRe -------------------------------------------------------------------------------- /test/payloads/payload.json: -------------------------------------------------------------------------------- 1 | { 2 | "includeReason":true, 3 | "date": "2022-03-23T14:15:39Z" 4 | } -------------------------------------------------------------------------------- /test/payloads/payload.txt: -------------------------------------------------------------------------------- 1 | includeReason: true, date: { seconds: 1648044939, nanos: 152000000 } -------------------------------------------------------------------------------- /test/proto/happyday.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package happyday; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | 7 | message HappyDayRequest { 8 | google.protobuf.Timestamp date = 1; 9 | bool includeReason = 2; 10 | 11 | /* use various data-types for testing here */ 12 | double double = 3; 13 | int32 int32 = 4; 14 | int64 int64 = 5; 15 | string string = 6; 16 | bytes bytes = 7; 17 | Foo fooEnum = 8; 18 | repeated MiscInfo misc = 9; 19 | float float = 10; 20 | string NonCamel_case_FieldName = 11; 21 | } 22 | 23 | message HappyDayResponse { 24 | bool isHappyDay = 1; 25 | string reason = 2; 26 | string formattedDate = 3; 27 | string err = 4; 28 | } 29 | 30 | enum Foo { 31 | BAR = 0; 32 | BAZ = 1; 33 | FAZ = 2; 34 | } 35 | 36 | message MiscInfo { 37 | repeated string weatherOfPastFewDays = 1; 38 | oneof alternative { 39 | string fooString = 2; 40 | Foo fooEnum = 3; 41 | } 42 | } -------------------------------------------------------------------------------- /test/proto/nameClashTest.proto.inactive: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package otherPackage; 3 | message HappyDayRequest { 4 | bool thisMessageWillCauseNameClash = 1; 5 | bool includeReason = 2; 6 | } 7 | enum ThisIsAnEnum { 8 | A = 0; 9 | B = 1; 10 | } 11 | message OtherResponse { 12 | bool isHappyDay = 1; 13 | string reason = 2; 14 | string formattedDate = 3; 15 | string err = 4; 16 | } -------------------------------------------------------------------------------- /test/results/.gitignore: -------------------------------------------------------------------------------- 1 | *-out.txt 2 | *-tmp.txt 3 | 4 | -------------------------------------------------------------------------------- /test/results/additional-curl-args--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Request Binary =========================== >>> 9 | 00000000 0a 0b 08 8b bc fe 8e 06 10 80 ac bd 48 10 01 |............H..| 10 | =========================== GET Response Headers =========================== <<< 11 | HTTP/1.1 200 OK 12 | Content-Type: application/x-protobuf 13 | Date: Thu, 05 Oct 2023 09:18:01 GMT 14 | Connection: keep-alive 15 | Keep-Alive: timeout=5 16 | Content-Length: 65 17 | =========================== GET Response Binary =========================== <<< 18 | 00000000 08 01 12 1c 54 68 75 72 73 64 61 79 20 69 73 20 |....Thursday is | 19 | 00000010 61 20 48 61 70 70 79 20 44 61 79 21 20 e2 ad 90 |a Happy Day! ...| 20 | 00000020 1a 1d 54 68 75 2c 20 31 33 20 4a 61 6e 20 32 30 |..Thu, 13 Jan 20| 21 | 00000030 32 32 20 30 33 3a 33 35 3a 33 39 20 47 4d 54 22 |22 03:35:39 GMT"| 22 | 00000040 00 |.| 23 | =========================== GET Response Text =========================== <<< 24 | isHappyDay: true 25 | reason: "Thursday is a Happy Day! ⭐" 26 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/additional-curl-args-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Request Binary =========================== >>> 9 | 00000000 0a 0b 08 8b bc fe 8e 06 10 80 ac bd 48 10 01 |............H..| 10 | =========================== POST Response Headers =========================== <<< 11 | HTTP/1.1 200 OK 12 | Content-Type: application/x-protobuf 13 | Date: Thu, 05 Oct 2023 09:18:00 GMT 14 | Connection: keep-alive 15 | Keep-Alive: timeout=5 16 | Content-Length: 65 17 | =========================== POST Response Binary =========================== <<< 18 | 00000000 08 01 12 1c 54 68 75 72 73 64 61 79 20 69 73 20 |....Thursday is | 19 | 00000010 61 20 48 61 70 70 79 20 44 61 79 21 20 e2 ad 90 |a Happy Day! ...| 20 | 00000020 1a 1d 54 68 75 2c 20 31 33 20 4a 61 6e 20 32 30 |..Thu, 13 Jan 20| 21 | 00000030 32 32 20 30 33 3a 33 35 3a 33 39 20 47 4d 54 22 |22 03:35:39 GMT"| 22 | 00000040 00 |.| 23 | =========================== POST Response Text =========================== <<< 24 | isHappyDay: true 25 | reason: "Thursday is a Happy Day! ⭐" 26 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/additional-curl-args-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Both --curl and --no-curl are active. 4 | I cannot use and not use curl. 5 | Please check the supplied and implied arguments via -v. 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/display-binary-and-headers--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Request Binary =========================== >>> 9 | 00000000 0a 0b 08 8b bc fe 8e 06 10 80 ac bd 48 10 01 |............H..| 10 | =========================== GET Response Headers =========================== <<< 11 | HTTP/1.1 200 OK 12 | Content-Type: application/x-protobuf 13 | Date: Thu, 05 Oct 2023 09:18:00 GMT 14 | Connection: keep-alive 15 | Keep-Alive: timeout=5 16 | Content-Length: 65 17 | =========================== GET Response Binary =========================== <<< 18 | 00000000 08 01 12 1c 54 68 75 72 73 64 61 79 20 69 73 20 |....Thursday is | 19 | 00000010 61 20 48 61 70 70 79 20 44 61 79 21 20 e2 ad 90 |a Happy Day! ...| 20 | 00000020 1a 1d 54 68 75 2c 20 31 33 20 4a 61 6e 20 32 30 |..Thu, 13 Jan 20| 21 | 00000030 32 32 20 30 33 3a 33 35 3a 33 39 20 47 4d 54 22 |22 03:35:39 GMT"| 22 | 00000040 00 |.| 23 | =========================== GET Response Text =========================== <<< 24 | isHappyDay: true 25 | reason: "Thursday is a Happy Day! ⭐" 26 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/display-binary-and-headers-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Request Binary =========================== >>> 9 | 00000000 0a 0b 08 8b bc fe 8e 06 10 80 ac bd 48 10 01 |............H..| 10 | =========================== POST Response Headers =========================== <<< 11 | HTTP/1.1 200 OK 12 | Content-Type: application/x-protobuf 13 | Date: Thu, 05 Oct 2023 09:17:59 GMT 14 | Connection: keep-alive 15 | Keep-Alive: timeout=5 16 | Content-Length: 65 17 | =========================== POST Response Binary =========================== <<< 18 | 00000000 08 01 12 1c 54 68 75 72 73 64 61 79 20 69 73 20 |....Thursday is | 19 | 00000010 61 20 48 61 70 70 79 20 44 61 79 21 20 e2 ad 90 |a Happy Day! ...| 20 | 00000020 1a 1d 54 68 75 2c 20 31 33 20 4a 61 6e 20 32 30 |..Thu, 13 Jan 20| 21 | 00000030 32 32 20 30 33 3a 33 35 3a 33 39 20 47 4d 54 22 |22 03:35:39 GMT"| 22 | 00000040 00 |.| 23 | =========================== POST Response Text =========================== <<< 24 | isHappyDay: true 25 | reason: "Thursday is a Happy Day! ⭐" 26 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/display-binary-and-headers-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Request Binary =========================== >>> 9 | 00000000 0a 0b 08 8b bc fe 8e 06 10 80 ac bd 48 10 01 |............H..| 10 | =========================== POST Response Headers =========================== <<< 11 | HTTP/1.1 200 OK 12 | Content-Length: 65 13 | Connection: keep-alive 14 | Content-Type: application/x-protobuf 15 | Date: Thu, 05 Oct 2023 09:17:59 GMT 16 | Keep-Alive: timeout=5 17 | =========================== POST Response Binary =========================== <<< 18 | 00000000 08 01 12 1c 54 68 75 72 73 64 61 79 20 69 73 20 |....Thursday is | 19 | 00000010 61 20 48 61 70 70 79 20 44 61 79 21 20 e2 ad 90 |a Happy Day! ...| 20 | 00000020 1a 1d 54 68 75 2c 20 31 33 20 4a 61 6e 20 32 30 |..Thu, 13 Jan 20| 21 | 00000030 32 32 20 30 33 3a 33 35 3a 33 39 20 47 4d 54 22 |22 03:35:39 GMT"| 22 | 00000040 00 |.| 23 | =========================== POST Response Text =========================== <<< 24 | isHappyDay: true 25 | reason: "Thursday is a Happy Day! ⭐" 26 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/echo-empty--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | 4 | =========================== GET Response Text =========================== <<< 5 | 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-empty--X_HEAD-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== HEAD Request Text =========================== >>> 3 | 4 | =========================== HEAD Response Text =========================== <<< 5 | 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-empty--X_HEAD_--no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== HEAD Request Text =========================== >>> 3 | 4 | ######### STDERR ######### 5 | Error: HTTP method HEAD not supported with internal HTTP implementation. Please use curl. 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/echo-empty-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | =========================== POST Response Text =========================== <<< 5 | 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-empty-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | =========================== POST Response Text =========================== <<< 5 | 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-empty-with-curl-args--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== CURL ERROR =========================== 5 | * Trying 127.0.0.1:8080... 6 | * Connected to localhost (127.0.0.1) port 8080 (#0) 7 | > GET /echo HTTP/1.1 8 | > Host: localhost:8080 9 | > User-Agent: curl/7.88.1 10 | > Accept: */* 11 | > Content-Type: application/x-protobuf 12 | > Content-Length: 2 13 | > 14 | } [2 bytes data] 15 | < HTTP/1.1 200 OK 16 | < Content-Type: application/x-protobuf 17 | < Date: Wed, 19 Mar 2025 14:18:42 GMT 18 | < Connection: keep-alive 19 | < Keep-Alive: timeout=5 20 | < Content-Length: 2 21 | < 22 | { [2 bytes data] 23 | * Connection #0 to host localhost left intact 24 | 25 | =========================== GET Response Text =========================== <<< 26 | includeReason: true 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/echo-empty-with-curl-args-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== CURL ERROR =========================== 5 | * Trying 127.0.0.1:8080... 6 | * Connected to localhost (127.0.0.1) port 8080 (#0) 7 | > POST /echo HTTP/1.1 8 | > Host: localhost:8080 9 | > User-Agent: curl/7.88.1 10 | > Accept: */* 11 | > Content-Type: application/x-protobuf 12 | > Content-Length: 2 13 | > 14 | } [2 bytes data] 15 | < HTTP/1.1 200 OK 16 | < Content-Type: application/x-protobuf 17 | < Date: Wed, 19 Mar 2025 14:18:41 GMT 18 | < Connection: keep-alive 19 | < Keep-Alive: timeout=5 20 | < Content-Length: 2 21 | < 22 | { [2 bytes data] 23 | * Connection #0 to host localhost left intact 24 | 25 | =========================== POST Response Text =========================== <<< 26 | includeReason: true 27 | ######### STDERR ######### 28 | ######### EXIT 0 ######### 29 | -------------------------------------------------------------------------------- /test/results/echo-empty-with-curl-args-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Both --curl and --no-curl are active. 4 | I cannot use and not use curl. 5 | Please check the supplied and implied arguments via -v. 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/echo-filled--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | date: { 10 | seconds: 1648044939 11 | nanos: 152000000 12 | } 13 | includeReason: true 14 | ######### STDERR ######### 15 | ######### EXIT 0 ######### 16 | -------------------------------------------------------------------------------- /test/results/echo-filled-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | date: { 10 | seconds: 1648044939 11 | nanos: 152000000 12 | } 13 | includeReason: true 14 | ######### STDERR ######### 15 | ######### EXIT 0 ######### 16 | -------------------------------------------------------------------------------- /test/results/echo-filled-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | date: { 10 | seconds: 1648044939 11 | nanos: 152000000 12 | } 13 | includeReason: true 14 | ######### STDERR ######### 15 | ######### EXIT 0 ######### 16 | -------------------------------------------------------------------------------- /test/results/echo-full--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | double: 0.12346789 9 | int32: 123123123 10 | int64: 123123123123123 11 | string: "some string here" 12 | bytes: "\x00\x01\x02\xff\xfe\xfd" 13 | fooEnum: BAZ 14 | misc: {} 15 | misc: { 16 | weatherOfPastFewDays: "1" 17 | weatherOfPastFewDays: "2" 18 | fooEnum: FAZ 19 | } 20 | misc: { 21 | fooString: "abc" 22 | } 23 | float: 0.123 24 | =========================== GET Response Text =========================== <<< 25 | date: { 26 | seconds: 1648044939 27 | nanos: 152000000 28 | } 29 | includeReason: true 30 | double: 0.12346789 31 | int32: 123123123 32 | int64: 123123123123123 33 | string: "some string here" 34 | bytes: "\x00\x01\x02\xff\xfe\xfd" 35 | fooEnum: BAZ 36 | misc: {} 37 | misc: { 38 | weatherOfPastFewDays: "1" 39 | weatherOfPastFewDays: "2" 40 | fooEnum: FAZ 41 | } 42 | misc: { 43 | fooString: "abc" 44 | } 45 | float: 0.123 46 | ######### STDERR ######### 47 | ######### EXIT 0 ######### 48 | -------------------------------------------------------------------------------- /test/results/echo-full-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | double: 0.12346789 9 | int32: 123123123 10 | int64: 123123123123123 11 | string: "some string here" 12 | bytes: "\x00\x01\x02\xff\xfe\xfd" 13 | fooEnum: BAZ 14 | misc: {} 15 | misc: { 16 | weatherOfPastFewDays: "1" 17 | weatherOfPastFewDays: "2" 18 | fooEnum: FAZ 19 | } 20 | misc: { 21 | fooString: "abc" 22 | } 23 | float: 0.123 24 | =========================== POST Response Text =========================== <<< 25 | date: { 26 | seconds: 1648044939 27 | nanos: 152000000 28 | } 29 | includeReason: true 30 | double: 0.12346789 31 | int32: 123123123 32 | int64: 123123123123123 33 | string: "some string here" 34 | bytes: "\x00\x01\x02\xff\xfe\xfd" 35 | fooEnum: BAZ 36 | misc: {} 37 | misc: { 38 | weatherOfPastFewDays: "1" 39 | weatherOfPastFewDays: "2" 40 | fooEnum: FAZ 41 | } 42 | misc: { 43 | fooString: "abc" 44 | } 45 | float: 0.123 46 | ######### STDERR ######### 47 | ######### EXIT 0 ######### 48 | -------------------------------------------------------------------------------- /test/results/echo-full-json--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"includeReason":true,"double":0.12346789,"int32":123123123,"int64":"123123123123123","string":"some string here","bytes":"AAEC//79","fooEnum":"BAZ","misc":[{},{"weatherOfPastFewDays":["1","2"],"fooEnum":"FAZ"},{"fooString":"abc"}],"float":0.123} 4 | =========================== GET Response JSON =========================== <<< 5 | {"includeReason":true,"double":0.12346789,"int32":123123123,"int64":"123123123123123","string":"some string here","bytes":"AAEC//79","fooEnum":"BAZ","misc":[{},{"weatherOfPastFewDays":["1","2"],"fooEnum":"FAZ"},{"fooString":"abc"}],"float":0.123} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-full-json-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"includeReason":true,"double":0.12346789,"int32":123123123,"int64":"123123123123123","string":"some string here","bytes":"AAEC//79","fooEnum":"BAZ","misc":[{},{"weatherOfPastFewDays":["1","2"],"fooEnum":"FAZ"},{"fooString":"abc"}],"float":0.123} 4 | =========================== POST Response JSON =========================== <<< 5 | {"includeReason":true,"double":0.12346789,"int32":123123123,"int64":"123123123123123","string":"some string here","bytes":"AAEC//79","fooEnum":"BAZ","misc":[{},{"weatherOfPastFewDays":["1","2"],"fooEnum":"FAZ"},{"fooString":"abc"}],"float":0.123} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/echo-full-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | double: 0.12346789 9 | int32: 123123123 10 | int64: 123123123123123 11 | string: "some string here" 12 | bytes: "\x00\x01\x02\xff\xfe\xfd" 13 | fooEnum: BAZ 14 | misc: {} 15 | misc: { 16 | weatherOfPastFewDays: "1" 17 | weatherOfPastFewDays: "2" 18 | fooEnum: FAZ 19 | } 20 | misc: { 21 | fooString: "abc" 22 | } 23 | float: 0.123 24 | =========================== POST Response Text =========================== <<< 25 | date: { 26 | seconds: 1648044939 27 | nanos: 152000000 28 | } 29 | includeReason: true 30 | double: 0.12346789 31 | int32: 123123123 32 | int64: 123123123123123 33 | string: "some string here" 34 | bytes: "\x00\x01\x02\xff\xfe\xfd" 35 | fooEnum: BAZ 36 | misc: {} 37 | misc: { 38 | weatherOfPastFewDays: "1" 39 | weatherOfPastFewDays: "2" 40 | fooEnum: FAZ 41 | } 42 | misc: { 43 | fooString: "abc" 44 | } 45 | float: 0.123 46 | ######### STDERR ######### 47 | ######### EXIT 0 ######### 48 | -------------------------------------------------------------------------------- /test/results/echo-quiet--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | date: { 3 | seconds: 1648044939 4 | nanos: 152000000 5 | } 6 | includeReason: true 7 | double: 0.12346789 8 | int32: 123123123 9 | int64: 123123123123123 10 | float: 0.123 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/echo-quiet-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | date: { 3 | seconds: 1648044939 4 | nanos: 152000000 5 | } 6 | includeReason: true 7 | double: 0.12346789 8 | int32: 123123123 9 | int64: 123123123123123 10 | float: 0.123 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/echo-quiet-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | date: { 3 | seconds: 1648044939 4 | nanos: 152000000 5 | } 6 | includeReason: true 7 | double: 0.12346789 8 | int32: 123123123 9 | int64: 123123123123123 10 | float: 0.123 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday-missing-curl--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | ######### STDERR ######### 5 | Error: Internal Http implementation doesn't support GET requests with body. Please use curl. 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday-missing-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday-missing-curl-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/empty-day-epoch-time-thursday-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/failure-simple--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | 4 | ######### STDERR ######### 5 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/failure-simple-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | ######### STDERR ######### 5 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/failure-simple-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | ######### STDERR ######### 5 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/failure-simple-quiet--D-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-quiet--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-quiet--v-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-quiet-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-quiet-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent--D-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent--q-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent--v-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/failure-simple-silent-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Request was unsuccessful. Received response status code outside of 2XX. Got: HTTP/1.1 404 Not Found 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/far-future--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 123231648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | err: "Cannot handle number of millis 123231648044939152 as number: 123231648044939150\n" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/far-future-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 123231648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | err: "Cannot handle number of millis 123231648044939152 as number: 123231648044939150\n" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/far-future-json--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"date":"9999-12-31T23:59:59Z","includeReason":true} 4 | =========================== GET Response JSON =========================== <<< 5 | {"isHappyDay":true,"reason":"Friday is a Happy Day! ⭐","formattedDate":"Fri, 31 Dec 9999 23:59:59 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/far-future-json-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"9999-12-31T23:59:59Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"isHappyDay":true,"reason":"Friday is a Happy Day! ⭐","formattedDate":"Fri, 31 Dec 9999 23:59:59 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/far-future-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 123231648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | err: "Cannot handle number of millis 123231648044939152 as number: 123231648044939150\n" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/global-protoc--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | /usr/bin/include: warning: directory does not exist. 6 | google/protobuf/timestamp.proto: File not found. 7 | /proto/happyday.proto:5:1: Import "google/protobuf/timestamp.proto" was not found or had errors. 8 | /proto/happyday.proto:8:3: "google.protobuf.Timestamp" is not defined. 9 | 10 | Underlying error: exit status 1 11 | ######### EXIT 1 ######### 12 | -------------------------------------------------------------------------------- /test/results/global-protoc-and-lib--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/global-protoc-and-lib-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/global-protoc-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | /usr/bin/include: warning: directory does not exist. 6 | google/protobuf/timestamp.proto: File not found. 7 | /proto/happyday.proto:5:1: Import "google/protobuf/timestamp.proto" was not found or had errors. 8 | /proto/happyday.proto:8:3: "google.protobuf.Timestamp" is not defined. 9 | 10 | Underlying error: exit status 1 11 | ######### EXIT 1 ######### 12 | -------------------------------------------------------------------------------- /test/results/help--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl , build , https://github.com/qaware/protocurl 3 | 4 | protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats. 5 | 6 | Usage: 7 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 8 | 9 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 10 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 11 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 12 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 13 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 14 | When converting between binary and text, the encoding UTF-8 is always used. 15 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 16 | 17 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 18 | 19 | Examples: 20 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 21 | 22 | Flags: 23 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 24 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 25 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 26 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 27 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 28 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 29 | -h, --help help for protocurl 30 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 31 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 32 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 33 | --no-curl Forces the use of the built-in internal http request instead of curl. 34 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 35 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 36 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 37 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 38 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 39 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 40 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 41 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 42 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 43 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 44 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 45 | -u, --url string Mandatory: The url to send the request to 46 | -v, --verbose Prints version and enables verbose output. Also activates -D. 47 | --version version for protocurl 48 | ######### STDERR ######### 49 | ######### EXIT 0 ######### 50 | -------------------------------------------------------------------------------- /test/results/help-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl , build , https://github.com/qaware/protocurl 3 | 4 | protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats. 5 | 6 | Usage: 7 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 8 | 9 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 10 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 11 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 12 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 13 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 14 | When converting between binary and text, the encoding UTF-8 is always used. 15 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 16 | 17 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 18 | 19 | Examples: 20 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 21 | 22 | Flags: 23 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 24 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 25 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 26 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 27 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 28 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 29 | -h, --help help for protocurl 30 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 31 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 32 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 33 | --no-curl Forces the use of the built-in internal http request instead of curl. 34 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 35 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 36 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 37 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 38 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 39 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 40 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 41 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 42 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 43 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 44 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 45 | -u, --url string Mandatory: The url to send the request to 46 | -v, --verbose Prints version and enables verbose output. Also activates -D. 47 | --version version for protocurl 48 | ######### STDERR ######### 49 | ######### EXIT 0 ######### 50 | -------------------------------------------------------------------------------- /test/results/help-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl , build , https://github.com/qaware/protocurl 3 | 4 | protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats. 5 | 6 | Usage: 7 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 8 | 9 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 10 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 11 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 12 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 13 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 14 | When converting between binary and text, the encoding UTF-8 is always used. 15 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 16 | 17 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 18 | 19 | Examples: 20 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 21 | 22 | Flags: 23 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 24 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 25 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 26 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 27 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 28 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 29 | -h, --help help for protocurl 30 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 31 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 32 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 33 | --no-curl Forces the use of the built-in internal http request instead of curl. 34 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 35 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 36 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 37 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 38 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 39 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 40 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 41 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 42 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 43 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 44 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 45 | -u, --url string Mandatory: The url to send the request to 46 | -v, --verbose Prints version and enables verbose output. Also activates -D. 47 | --version version for protocurl 48 | ######### STDERR ######### 49 | ######### EXIT 0 ######### 50 | -------------------------------------------------------------------------------- /test/results/in-wrong--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Unknown input format bad. Expected text or json for --in 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/in-wrong-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Unknown input format bad. Expected text or json for --in 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/infer-files-provide-file-wrong-args--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Both -F is set and -f is provided. Please provide only one of these. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/infer-files-provide-file-wrong-args-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Both -F is set and -f is provided. Please provide only one of these. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-name-clash-ambiguous-error--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Message with base name is not unique. Found 2 messages with package paths: [happyday.HappyDayRequest otherPackage.HappyDayRequest] 4 | Try -v verbose or specify the file explicitly via -f . 5 | ######### EXIT 1 ######### 6 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-name-clash-ambiguous-error-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Message with base name is not unique. Found 2 messages with package paths: [happyday.HappyDayRequest otherPackage.HappyDayRequest] 4 | Try -v verbose or specify the file explicitly via -f . 5 | ######### EXIT 1 ######### 6 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-nested--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-nested-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-nested-subdir--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/inferred-message-package-path-nested-subdir-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file--F-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file--F_-X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file-message-package-path--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/inferred-proto-file-message-package-path-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/invalid-protofile-dir--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | does-not-exist: warning: directory does not exist. 6 | Could not make proto path relative: does-not-exist/happyday.proto: No such file or directory 7 | 8 | Underlying error: exit status 1 9 | ######### EXIT 1 ######### 10 | -------------------------------------------------------------------------------- /test/results/invalid-protofile-dir-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | does-not-exist: warning: directory does not exist. 6 | Could not make proto path relative: does-not-exist/happyday.proto: No such file or directory 7 | 8 | Underlying error: exit status 1 9 | ######### EXIT 1 ######### 10 | -------------------------------------------------------------------------------- /test/results/invalid-protofile-path--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | Could not make proto path relative: /proto/does-not-exist.proto: No such file or directory 6 | 7 | Underlying error: exit status 1 8 | ######### EXIT 1 ######### 9 | -------------------------------------------------------------------------------- /test/results/invalid-protofile-path-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 4 | protoc stderr: 5 | Could not make proto path relative: /proto/does-not-exist.proto: No such file or directory 6 | 7 | Underlying error: exit status 1 8 | ######### EXIT 1 ######### 9 | -------------------------------------------------------------------------------- /test/results/json-in--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== GET Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/json-in-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/json-in-proper-proto-names--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true,"NonCamel_case_FieldName":"text"} 4 | =========================== GET Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/json-in-proper-proto-names-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true,"NonCamel_case_FieldName":"text"} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/json-in-wrong-arg--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Specified input format text is different from inferred format json. Please check your arguments. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/json-in-wrong-arg-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Specified input format text is different from inferred format json. Please check your arguments. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/json-out-pretty--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== GET Response JSON =========================== <<< 5 | { 6 | "reason": "Tough luck on Wednesday... 😕", 7 | "formattedDate": "Wed, 23 Mar 2022 14:15:39 GMT" 8 | } 9 | ######### STDERR ######### 10 | ######### EXIT 0 ######### 11 | -------------------------------------------------------------------------------- /test/results/json-out-pretty-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | { 6 | "reason": "Tough luck on Wednesday... 😕", 7 | "formattedDate": "Wed, 23 Mar 2022 14:15:39 GMT" 8 | } 9 | ######### STDERR ######### 10 | ######### EXIT 0 ######### 11 | -------------------------------------------------------------------------------- /test/results/message-package-path-nested-subdir--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/message-package-path-nested-subdir-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/message-package-path-resolved-to-non-message-error--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: I couldn't find any Protobuf message for the message package-path otherPackage.ThisIsAnEnum. 4 | Did you correctly -I (include) your proto files directory? 5 | Did you correctly specify the full message package-path to your Protobuf message type? 6 | Try again with -v (verbose). 7 | Underlying error: could not convert descriptor to protoreflect.MessageDescriptor: 8 | EnumDescriptor{Syntax: proto3, FullName: otherPackage.ThisIsAnEnum, Values: [{Name: A},{Name: B, Number: 1}]} 9 | ######### EXIT 1 ######### 10 | -------------------------------------------------------------------------------- /test/results/message-package-path-resolved-to-non-message-error-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: I couldn't find any Protobuf message for the message package-path otherPackage.ThisIsAnEnum. 4 | Did you correctly -I (include) your proto files directory? 5 | Did you correctly specify the full message package-path to your Protobuf message type? 6 | Try again with -v (verbose). 7 | Underlying error: could not convert descriptor to protoreflect.MessageDescriptor: 8 | EnumDescriptor{Syntax: proto3, FullName: otherPackage.ThisIsAnEnum, Values: [{Name: A},{Name: B, Number: 1}]} 9 | ######### EXIT 1 ######### 10 | -------------------------------------------------------------------------------- /test/results/missing-args--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-args-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-args-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-args-partial--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-args-partial-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-args-partial-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: required flag(s) "url" not set 4 | Usage: 5 | protocurl [flags] -I proto-dir -i request-type -o response-type -u url -d request-text 6 | 7 | It uses 'curl' from PATH. If none was found, it will fall back to an internal non-configurable http request. 8 | It uses a bundled 'protoc' (by default) which is used to parse the .proto files. 9 | The bundle also includes the well-known Google Protobuf files necessary to create FileDescriptorSet payloads via 'protoc'. 10 | If the bundled 'protoc' is used, then these .proto files are included. Otherwise .proto files from the system-wide include are used. 11 | The Header 'Content-Type: application/x-protobuf' is set as a request header by default. (disable via -n) 12 | When converting between binary and text, the encoding UTF-8 is always used. 13 | When the correct response type is unknown or being debugged, omitting -o will attempt to show the response in raw format. 14 | 15 | Enhancements and bugs: https://github.com/qaware/protocurl/issues 16 | 17 | Examples: 18 | protocurl -I my-protos -i package.path.Req -o package.path.Resp -u http://example.com/api -d "myField: true, otherField: 1337" 19 | 20 | Flags: 21 | --curl Forces the use of curl executable found in PATH. If none was found, then exits with an error. 22 | -C, --curl-args string Additional cURL args which will be passed on to cURL during request invocation for further configuration. Also activates --curl. 23 | --curl-path string Uses the given path to invoke curl instead of searching for curl in PATH. Also activates --curl. 24 | -d, --data-text-or-file string The payload data in Protobuf text format or JSON supplied as a string or a filepath (if first character is '@'). The string is inferred from the input as JSON if the first token is a '{'.The format can be set explicitly via --in. Mandatory if request-type is provided.See https://github.com/qaware/protocurl 25 | --decode-raw Decode the response into textual format without the schema by only showing field numbers and inferred field types. Types may be incorrect. Only output format text is supported. Use -o to see correct contents. 26 | -D, --display-binary-and-http Displays the binary request and response as well as the non-binary response headers. 27 | -h, --help help for protocurl 28 | --in string Specifies, in which format the input -d should be interpreted in. 'text' (default) uses the Protobuf text format and 'json' uses JSON. The type is inferred as JSON if the first token is a '{'. 29 | -F, --infer-files Infer the correct files containing the relevant protobuf messages. All proto files in the proto directory provided by -I will be used. If no -f is provided, this -F is set and the files are inferred. 30 | -X, --method string HTTP request method. POST and GET are explicitly supported. Other methods are passed on to curl optimistically. (default "POST") 31 | --no-curl Forces the use of the built-in internal http request instead of curl. 32 | -n, --no-default-headers Default headers (e.g. "Content-Type") will not be passed to curl. Assumes --curl. Use "-n -H 'Content-Type: FooBar'" to override the default content type. 33 | --out string Produces the output in the specified format. 'text' (default) produces Protobuf text format. 'json' produces dense JSON and 'json:pretty' produces pretty-printed JSON. The produced JSON always uses the original Protobuf field names instead of lowerCamelCasing them. 34 | -I, --proto-dir string Uses the specified directory to find the proto-file. (default "/proto") 35 | -f, --proto-file string Uses the specified file path to find the Protobuf definition of the message types within 'proto-dir' (relative file path). 36 | --protoc Forces the use of a global protoc executable found in PATH or via --protoc-path instead of using the bundled one. If none was found, then exits with an error. 37 | --protoc-path string Uses the given path to invoke protoc instead of searching for protoc in PATH. Also activates --protoc. 38 | -H, --request-header string Adds the string header to the invocation of cURL. This option is not supported when --no-curl is active. E.g. -H 'MyHeader: FooBar'. 39 | -i, --request-type string Message name or full package path of the Protobuf request type. The path can be shortened to '..', if the name of the request message is unique. Mandatory for POST requests. E.g. mypackage.MyRequest or ..MyRequest 40 | -o, --response-type string The Protobuf response type. See -i . Overrides --decode-raw. If not set, then --decode-raw is used. 41 | -q, --show-output-only Suppresses all output except response Protobuf as text. Overrides and deactivates -v and -D. Errors are still printed to stderr. 42 | -s, --silent Suppresses all output on stdout. Overrides and deactivates -v, -D and -q. Errors are still printed to stderr. 43 | -u, --url string Mandatory: The url to send the request to 44 | -v, --verbose Prints version and enables verbose output. Also activates -D. 45 | --version version for protocurl 46 | 47 | Error: required flag(s) "url" not set 48 | ######### EXIT 1 ######### 49 | -------------------------------------------------------------------------------- /test/results/missing-curl-header-args-not-possible--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | ######### STDERR ######### 9 | Error: Non-default or custom headers are not supported when using internal http. Please provide curl in path and avoid using --no-curl. Found headers: ["Content-Type: application/x-protobuf" "x-abc: def"] 10 | ######### EXIT 1 ######### 11 | -------------------------------------------------------------------------------- /test/results/missing-curl-header-args-not-possible-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | ######### STDERR ######### 9 | Error: Non-default or custom headers are not supported when using internal http. Please provide curl in path and avoid using --no-curl. Found headers: ["Content-Type: application/x-protobuf" "x-abc: def"] 10 | ######### EXIT 1 ######### 11 | -------------------------------------------------------------------------------- /test/results/missing-curl-no-curl--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | ######### STDERR ######### 9 | Error: Internal Http implementation doesn't support GET requests with body. Please use curl. 10 | ######### EXIT 1 ######### 11 | -------------------------------------------------------------------------------- /test/results/missing-curl-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/missing-protoc--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "GET", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | ######### STDERR ######### 35 | Error: Could not find bundled executable protoc 36 | Error: stat /protocurl/protocurl-internal/bin/protoc: no such file or directory 37 | ######### EXIT 1 ######### 38 | -------------------------------------------------------------------------------- /test/results/missing-protoc-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "POST", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | ######### STDERR ######### 35 | Error: Could not find bundled executable protoc 36 | Error: stat /protocurl/protocurl-internal/bin/protoc: no such file or directory 37 | ######### EXIT 1 ######### 38 | -------------------------------------------------------------------------------- /test/results/missing-protoc-global--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "GET", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": true, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | GlobalProtoc is set, hence bundled protoc will be ignored. 35 | ######### STDERR ######### 36 | Error: I could not find a 'protoc' executable. Please check your PATH. 37 | Underlying error: exec: "protoc": executable file not found in $PATH 38 | ######### EXIT 1 ######### 39 | -------------------------------------------------------------------------------- /test/results/missing-protoc-global-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "POST", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": true, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | GlobalProtoc is set, hence bundled protoc will be ignored. 35 | ######### STDERR ######### 36 | Error: I could not find a 'protoc' executable. Please check your PATH. 37 | Underlying error: exec: "protoc": executable file not found in $PATH 38 | ######### EXIT 1 ######### 39 | -------------------------------------------------------------------------------- /test/results/missing-protocurl-internal--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "GET", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | ######### STDERR ######### 35 | Error: Cannot find 'protocurl-internal' directory. 36 | Please ensure that you correctly extracted the full protocurl archive. 37 | I was expecting to find a directory 'protocurl-internal' side by side 38 | to the bin directory containing the protocurl executable. 39 | The executable was found at /protocurl/bin/protocurl 40 | Error: lstat /protocurl/protocurl-internal: no such file or directory 41 | ######### EXIT 1 ######### 42 | -------------------------------------------------------------------------------- /test/results/missing-protocurl-internal-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "POST", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | ######### STDERR ######### 35 | Error: Cannot find 'protocurl-internal' directory. 36 | Please ensure that you correctly extracted the full protocurl archive. 37 | I was expecting to find a directory 'protocurl-internal' side by side 38 | to the bin directory containing the protocurl executable. 39 | The executable was found at /protocurl/bin/protocurl 40 | Error: lstat /protocurl/protocurl-internal: no such file or directory 41 | ######### EXIT 1 ######### 42 | -------------------------------------------------------------------------------- /test/results/moved-curl--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/moved-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | reason: "Thursday is a Happy Day! ⭐" 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/moved-curl-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Both --curl and --no-curl are active. 4 | I cannot use and not use curl. 5 | Please check the supplied and implied arguments via -v. 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/moved-lib--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "GET", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | Found bundled protoc at /protocurl/protocurl-internal/bin/protoc 35 | Using google protobuf include: /protocurl/protocurl-internal/include 36 | Converting all files in /proto to a FileDescriptorSet. 37 | Found .proto: happyday.proto 38 | ######### STDERR ######### 39 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 40 | protoc stderr: 41 | /protocurl/protocurl-internal/include: warning: directory does not exist. 42 | google/protobuf/timestamp.proto: File not found. 43 | /proto/happyday.proto:5:1: Import "google/protobuf/timestamp.proto" was not found or had errors. 44 | /proto/happyday.proto:8:3: "google.protobuf.Timestamp" is not defined. 45 | 46 | Underlying error: exit status 1 47 | ######### EXIT 1 ######### 48 | -------------------------------------------------------------------------------- /test/results/moved-lib-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | protocurl , build , https://github.com/qaware/protocurl 5 | Adding default header argument to request headers : [Content-Type: application/x-protobuf] 6 | Invoked with following default & parsed arguments: 7 | { 8 | "ProtoFilesDir": "/proto", 9 | "ProtoInputFilePath": "", 10 | "RequestType": "..HappyDayRequest", 11 | "ResponseType": "..HappyDayResponse", 12 | "Url": "http://localhost:8080/happy-day/verify", 13 | "Method": "POST", 14 | "DataText": "includeReason: true", 15 | "InTextType": "text", 16 | "OutTextType": "text", 17 | "DecodeRawResponse": false, 18 | "DisplayBinaryAndHttp": true, 19 | "NoDefaultHeaders": false, 20 | "RequestHeaders": [ 21 | "Content-Type: application/x-protobuf" 22 | ], 23 | "CustomCurlPath": "", 24 | "AdditionalCurlArgs": "", 25 | "Verbose": true, 26 | "ShowOutputOnly": false, 27 | "SilentMode": false, 28 | "ForceNoCurl": false, 29 | "ForceCurl": false, 30 | "GlobalProtoc": false, 31 | "CustomProtocPath": "", 32 | "InferProtoFiles": true 33 | } 34 | Found bundled protoc at /protocurl/protocurl-internal/bin/protoc 35 | Using google protobuf include: /protocurl/protocurl-internal/include 36 | Converting all files in /proto to a FileDescriptorSet. 37 | Found .proto: happyday.proto 38 | ######### STDERR ######### 39 | Error: Failed to convert input .proto to FileDescriptorSet. Error: exit status 1 40 | protoc stderr: 41 | /protocurl/protocurl-internal/include: warning: directory does not exist. 42 | google/protobuf/timestamp.proto: File not found. 43 | /proto/happyday.proto:5:1: Import "google/protobuf/timestamp.proto" was not found or had errors. 44 | /proto/happyday.proto:8:3: "google.protobuf.Timestamp" is not defined. 45 | 46 | Underlying error: exit status 1 47 | ######### EXIT 1 ######### 48 | -------------------------------------------------------------------------------- /test/results/no-reason--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | =========================== GET Response Text =========================== <<< 8 | isHappyDay: true 9 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/no-reason-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | =========================== POST Response Text =========================== <<< 8 | isHappyDay: true 9 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/no-reason-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | =========================== POST Response Text =========================== <<< 8 | isHappyDay: true 9 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 10 | ######### STDERR ######### 11 | ######### EXIT 0 ######### 12 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days-moved-protofiles--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days-moved-protofiles-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days-moved-protofiles-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/other-days-are-happy-days-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1642044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | isHappyDay: true 10 | reason: "Thursday is a Happy Day! ⭐" 11 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 12 | ######### STDERR ######### 13 | ######### EXIT 0 ######### 14 | -------------------------------------------------------------------------------- /test/results/out-wrong--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Unknown output format bad. Expected text, json or json:pretty for --out 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/out-wrong-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Unknown output format bad. Expected text, json or json:pretty for --out 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/payload-file-not-found-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: open /payloads/does-not-exist: no such file or directory 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/payload-invalid-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: proto: (line 1:1): unknown field: includeRe 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/payload-json-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/payload-json-relative-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/payload-txt-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/quiet-with-content--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | isHappyDay: true 3 | reason: "Thursday is a Happy Day! ⭐" 4 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 5 | ######### STDERR ######### 6 | ######### EXIT 0 ######### 7 | -------------------------------------------------------------------------------- /test/results/quiet-with-content-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | isHappyDay: true 3 | reason: "Thursday is a Happy Day! ⭐" 4 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 5 | ######### STDERR ######### 6 | ######### EXIT 0 ######### 7 | -------------------------------------------------------------------------------- /test/results/quiet-with-content-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | isHappyDay: true 3 | reason: "Thursday is a Happy Day! ⭐" 4 | formattedDate: "Thu, 13 Jan 2022 03:35:39 GMT" 5 | ######### STDERR ######### 6 | ######### EXIT 0 ######### 7 | -------------------------------------------------------------------------------- /test/results/silent-with-content--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | ######### EXIT 0 ######### 4 | -------------------------------------------------------------------------------- /test/results/silent-with-content-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | ######### EXIT 0 ######### 4 | -------------------------------------------------------------------------------- /test/results/silent-with-content-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | ######### EXIT 0 ######### 4 | -------------------------------------------------------------------------------- /test/results/text-in--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/text-in-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/text-in-wrong-arg--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Specified input format json is different from inferred format text. Please check your arguments. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/text-in-wrong-arg-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Specified input format json is different from inferred format text. Please check your arguments. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/tmp-file-permissions-readable--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | 4 | -rw-r--r-- 5 | =========================== GET Response Text =========================== <<< 6 | isHappyDay: true 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/tmp-file-permissions-readable-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | -rw-r--r-- 5 | =========================== POST Response Text =========================== <<< 6 | isHappyDay: true 7 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | ######### STDERR ######### 9 | ######### EXIT 0 ######### 10 | -------------------------------------------------------------------------------- /test/results/unknown-base-message-name-error--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: No message found with base name: DoesNotExist. Check the folder of proto files (-I) and verbose (-v). 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/unknown-base-message-name-error-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: No message found with base name: DoesNotExist. Check the folder of proto files (-I) and verbose (-v). 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/unknown-message-as-json--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Decoding of raw messages is not supported with output format json. Please use text instead. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/unknown-message-as-json-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Decoding of raw messages is not supported with output format json. Please use text instead. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/unknown-message-as-text--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | includeReason: true 4 | =========================== GET Response Text =========================== <<< 5 | 1: 1 6 | 2: "Thursday is a Happy Day! ⭐" 7 | 3: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | 4: "" 9 | ######### STDERR ######### 10 | ######### EXIT 0 ######### 11 | -------------------------------------------------------------------------------- /test/results/unknown-message-as-text-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | includeReason: true 4 | =========================== POST Response Text =========================== <<< 5 | 1: 1 6 | 2: "Thursday is a Happy Day! ⭐" 7 | 3: "Thu, 01 Jan 1970 00:00:00 GMT" 8 | 4: "" 9 | ######### STDERR ######### 10 | ######### EXIT 0 ######### 11 | -------------------------------------------------------------------------------- /test/results/unknown-message-package-path-error--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: I couldn't find any Protobuf message for the message package-path happyday.DoesNotExist. 4 | Did you correctly -I (include) your proto files directory? 5 | Did you correctly specify the full message package-path to your Protobuf message type? 6 | Try again with -v (verbose). 7 | Underlying error: proto: not found 8 | ######### EXIT 1 ######### 9 | -------------------------------------------------------------------------------- /test/results/unknown-message-package-path-error-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: I couldn't find any Protobuf message for the message package-path happyday.DoesNotExist. 4 | Did you correctly -I (include) your proto files directory? 5 | Did you correctly specify the full message package-path to your Protobuf message type? 6 | Try again with -v (verbose). 7 | Underlying error: proto: not found 8 | ######### EXIT 1 ######### 9 | -------------------------------------------------------------------------------- /test/results/verbose-custom-headers-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | Inferred input text type as text. 3 | Infering proto files (-F), since -f was not provided. 4 | ######### STDERR ######### 5 | Error: Non-default or custom headers are not supported when using internal http. Please provide curl in path and avoid using --no-curl. Found headers: ["x-abc: def" "x-ghi: jkl"] 6 | ######### EXIT 1 ######### 7 | -------------------------------------------------------------------------------- /test/results/version--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl version , build , https://github.com/qaware/protocurl 3 | ######### STDERR ######### 4 | ######### EXIT 0 ######### 5 | -------------------------------------------------------------------------------- /test/results/version-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl version , build , https://github.com/qaware/protocurl 3 | ######### STDERR ######### 4 | ######### EXIT 0 ######### 5 | -------------------------------------------------------------------------------- /test/results/version-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | protocurl version , build , https://github.com/qaware/protocurl 3 | ######### STDERR ######### 4 | ######### EXIT 0 ######### 5 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== GET Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day--X_POST-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day-json--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== GET Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day-json-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day-json-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request JSON =========================== >>> 3 | {"date":"2022-03-23T14:15:39Z","includeReason":true} 4 | =========================== POST Response JSON =========================== <<< 5 | {"reason":"Tough luck on Wednesday... 😕","formattedDate":"Wed, 23 Mar 2022 14:15:39 GMT"} 6 | ######### STDERR ######### 7 | ######### EXIT 0 ######### 8 | -------------------------------------------------------------------------------- /test/results/wednesday-is-not-a-happy-day-no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | date: { 4 | seconds: 1648044939 5 | nanos: 152000000 6 | } 7 | includeReason: true 8 | =========================== POST Response Text =========================== <<< 9 | reason: "Tough luck on Wednesday... 😕" 10 | formattedDate: "Wed, 23 Mar 2022 14:15:39 GMT" 11 | ######### STDERR ######### 12 | ######### EXIT 0 ######### 13 | -------------------------------------------------------------------------------- /test/results/without-input--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Response Text =========================== <<< 3 | isHappyDay: true 4 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 5 | ######### STDERR ######### 6 | ######### EXIT 0 ######### 7 | -------------------------------------------------------------------------------- /test/results/without-input--X_GET_--no-curl-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Response Text =========================== <<< 3 | isHappyDay: true 4 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 5 | ######### STDERR ######### 6 | ######### EXIT 0 ######### 7 | -------------------------------------------------------------------------------- /test/results/without-input--X_GET_-i___HappyDayRequest-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== GET Request Text =========================== >>> 3 | 4 | =========================== GET Response Text =========================== <<< 5 | isHappyDay: true 6 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 7 | ######### STDERR ######### 8 | ######### EXIT 0 ######### 9 | -------------------------------------------------------------------------------- /test/results/without-input--i___HappyDayRequest-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | =========================== POST Request Text =========================== >>> 3 | 4 | =========================== POST Response Text =========================== <<< 5 | isHappyDay: true 6 | formattedDate: "Thu, 01 Jan 1970 00:00:00 GMT" 7 | ######### STDERR ######### 8 | ######### EXIT 0 ######### 9 | -------------------------------------------------------------------------------- /test/results/without-input-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: With method POST, a request type and the data text is needed. However, request type was not provided. Aborting. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/without-request-type--X_GET-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: Non-empty data-body was provided, but no request type was given. Hence, encoding of data-body is not possible. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/results/without-request-type-expected.txt: -------------------------------------------------------------------------------- 1 | ######### STDOUT ######### 2 | ######### STDERR ######### 3 | Error: With method POST, a request type and the data text is needed. However, request type was not provided. Aborting. 4 | ######### EXIT 1 ######### 5 | -------------------------------------------------------------------------------- /test/servers/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /test/servers/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM library/node:17.7.2 2 | # Keep this version in sync with release.yml 3 | WORKDIR /servers 4 | COPY test/servers/package*.json ./ 5 | RUN npm ci 6 | COPY test/servers/. . 7 | COPY test/proto ./proto 8 | # When updating this setup, we also need to adapt the windows-test-server.ps1 9 | # since that is used for the windows ci. -------------------------------------------------------------------------------- /test/servers/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | server: 4 | build: 5 | dockerfile: ./test/servers/Dockerfile 6 | context: ../.. 7 | image: nodeserver:v1 8 | container_name: protocurl-node-server 9 | ports: 10 | - 8080:8080 11 | command: npm start 12 | -------------------------------------------------------------------------------- /test/servers/native-start-server.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | # Run this script with "test" as the working directory 4 | 5 | npm install -g forever 6 | 7 | Write-Output "Install server..." 8 | # Replicate steps from Dockerfile 9 | cd servers 10 | npm ci 11 | node ./node_modules/typescript/bin/tsc 12 | 13 | Write-Output "Before start server:" 14 | ls dist 15 | cd .. 16 | 17 | Write-Output "Starting server..." 18 | # runs in background 19 | forever start ./servers/dist/server.js 20 | Start-Sleep -s 8 21 | 22 | if (Get-Command 'Get-NetTCPConnection' -errorAction SilentlyContinue) { 23 | Write-Output "Check server is running at 8080..." 24 | Get-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess 25 | } 26 | else { 27 | Write-Output "I don't know how to check if the server is ready. Let's be lucky!" 28 | } -------------------------------------------------------------------------------- /test/servers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "servers", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/server.js", 6 | "scripts": { 7 | "start": "./node_modules/typescript/bin/tsc && node dist/server.js", 8 | "tsbuild": "./node_modules/typescript/bin/tsc" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "typescript": "^5.2.2" 14 | }, 15 | "dependencies": { 16 | "long": "^5.2.3", 17 | "protobufjs": "~7.5.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/suite/.gitignore: -------------------------------------------------------------------------------- 1 | run-testcases.sh 2 | tmp.Dockerfile 3 | -------------------------------------------------------------------------------- /test/suite/copy-test-results-output-to-expected.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | source test/suite/setup.sh 5 | 6 | # Copy each -out.txt to -expected.txt 7 | 8 | FILES="$(ls -a test/results/*-out.txt)" 9 | 10 | copyIfDiff() { 11 | meaningfulDiff "$1" "${1%"-out.txt"}-expected.txt" >/dev/null 12 | if [[ "$?" == "0" ]]; then 13 | echo "✅ ${1%"-out.txt"}" 14 | else 15 | cp "$1" "${1%"-out.txt"}-expected.txt" 16 | echo "▶️ ${1%"-out.txt"}" 17 | fi 18 | } 19 | export -f copyIfDiff 20 | 21 | echo "$FILES" | xargs -I + bash -c 'copyIfDiff "$@"' _ + 22 | -------------------------------------------------------------------------------- /test/suite/linux/install-test-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # should be run inside ./test folder within a container to test packaged linux releases 5 | 6 | OS_NAME="$1" 7 | EXT="$2" 8 | URL_NO_EXT="$3" 9 | 10 | source "./test/suite/linux/package-${OS_NAME}.sh" 11 | 12 | setup 13 | 14 | install "$URL_NO_EXT$EXT" 15 | 16 | pwsh test/suite/native-tests.ps1 "/opt/protocurl" "" "isNotLocalDirTests" 17 | 18 | # Overriding installation does not break 19 | install "$URL" 20 | 21 | pwsh test/suite/native-tests.ps1 "/opt/protocurl" "" "isNotLocalDirTests" 22 | 23 | remove 24 | 25 | [[ "$(which protocurl)" == "" ]] 26 | -------------------------------------------------------------------------------- /test/suite/linux/package-alpine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | set -x 4 | 5 | setup() { 6 | # Install powershell + curl + gcompat 7 | 8 | apk add --no-cache curl gcompat \ 9 | ca-certificates \ 10 | less \ 11 | ncurses-terminfo-base \ 12 | krb5-libs \ 13 | libgcc \ 14 | libintl \ 15 | libssl3 \ 16 | libstdc++ \ 17 | tzdata \ 18 | userspace-rcu \ 19 | zlib \ 20 | icu-libs 21 | 22 | apk -X https://dl-cdn.alpinelinux.org/alpine/edge/main add --no-cache lttng-ust 23 | # todo. auto-updating url? 24 | curl -L https://github.com/PowerShell/PowerShell/releases/download/v7.4.1/powershell-7.4.1-linux-musl-x64.tar.gz -o /tmp/powershell.tar.gz 25 | mkdir -p /opt/microsoft/powershell/7 26 | tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 27 | chmod +x /opt/microsoft/powershell/7/pwsh 28 | ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh 29 | } 30 | export -f setup 31 | 32 | install() { 33 | URL="$1" 34 | curl -sL -o protocurl.apk "$URL" 35 | ls /home 36 | apk add --allow-untrusted protocurl.apk 37 | } 38 | export -f install 39 | 40 | remove() { 41 | apk del protocurl 42 | } 43 | export -f remove 44 | -------------------------------------------------------------------------------- /test/suite/linux/package-debian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | setup() { 5 | apt-get update -q 6 | apt-get install -q -y curl gnupg apt-transport-https 7 | curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - 8 | sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-debian-bullseye-prod bullseye main" > /etc/apt/sources.list.d/microsoft.list' 9 | apt-get update -q && apt-get install -y powershell 10 | } 11 | export -f setup 12 | 13 | install() { 14 | URL="$1" 15 | curl -sL -o protocurl.deb "$URL" 16 | ls /home 17 | dpkg --install protocurl.deb 18 | } 19 | export -f install 20 | 21 | remove() { 22 | dpkg --remove protocurl 23 | } 24 | export -f remove 25 | -------------------------------------------------------------------------------- /test/suite/native-tests.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | # This script should be primarily run from CI. 4 | 5 | $pc = $args[0] 6 | $ExeExt = $args[1] 7 | $testFromLocalDirInstallation = $args[2] 8 | 9 | function AbortIfCommandFailed 10 | { 11 | if ($LASTEXITCODE -ne 0) { 12 | throw "Exit code is $LASTEXITCODE" 13 | } 14 | } 15 | 16 | function Run-Tests 17 | { 18 | param( 19 | $ProtocurlExec 20 | ) 21 | 22 | Write-Output "====== Running tests using executable $ProtocurlExec ======" 23 | 24 | Write-Output "=== Executable is runnable ===" 25 | &"$ProtocurlExec" -h 26 | AbortIfCommandFailed 27 | 28 | Write-Output "=== Base scenario runs. protoc$ExeExt is found and used. protocurl-internal is found and used ===" 29 | &"$ProtocurlExec" -I test/proto ` 30 | -f happyday.proto -i happyday.HappyDayRequest -o happyday.HappyDayResponse ` 31 | -u http://localhost:8080/happy-day/verify -d "includeReason: true" 32 | AbortIfCommandFailed 33 | 34 | Write-Output "=== GET request works without input ===" 35 | &"$ProtocurlExec" -I test/proto ` 36 | -X GET -f happyday.proto -o happyday.HappyDayResponse ` 37 | -u http://localhost:8080/happy-day/verify 38 | AbortIfCommandFailed 39 | 40 | Write-Output "=== Using custom protoc and proto lib and global curl ===" 41 | if (Test-Path my-protoc) { 42 | Remove-Item my-protoc -Recurse -force 43 | } 44 | mkdir my-protoc 45 | mkdir my-protoc/my-bin 46 | Copy-Item "$pc/protocurl-internal/bin/protoc$ExeExt" -Destination my-protoc/my-bin/protoc$ExeExt 47 | Copy-Item "$pc/protocurl-internal/include" -Destination my-protoc/my-protos -Recurse 48 | Copy-Item "test/proto/*" -Destination my-protoc/my-protos -Recurse 49 | 50 | &"$ProtocurlExec" -v --curl ` 51 | --protoc-path my-protoc/my-bin/protoc -I my-protoc/my-protos ` 52 | -f happyday.proto -i happyday.HappyDayRequest -o happyday.HappyDayResponse ` 53 | -u http://localhost:8080/happy-day/verify -d "includeReason: true" 54 | AbortIfCommandFailed 55 | } 56 | 57 | Write-Output "========= Running native tests =========" 58 | 59 | if ($testFromLocalDirInstallation -eq "localDirTests") { 60 | Run-Tests("./$pc/bin/protocurl$ExeExt") 61 | 62 | Write-Output "Installing protocurl into PATH and re-executing..." 63 | 64 | $EnvPathSeparator = "$( [IO.Path]::PathSeparator )" 65 | # ; on windows, : on unix 66 | 67 | $Env:PATH += "$EnvPathSeparator$PWD/$pc/bin" 68 | 69 | Write-Output "Path after installation: $Env:PATH" 70 | } 71 | 72 | Run-Tests("protocurl") 73 | 74 | Write-Output "========= Native Tests successful. =========" -------------------------------------------------------------------------------- /test/suite/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Test suite: Starts the server and sends multiple requests against it to check the log output 6 | 7 | if [[ "$#" == 0 ]]; then 8 | echo "Please provide the working directory as a a docker-mount friendly path." 9 | exit 1 10 | fi 11 | 12 | WORKING_DIR="$1" 13 | 14 | export RUN_CLIENT="docker run --rm -v $WORKING_DIR/test/proto:/proto -v $WORKING_DIR/test/payloads:/payloads --network host" 15 | 16 | export SHOW_LOGS="docker logs" 17 | 18 | export TESTS_SUCCESS="true" 19 | 20 | source test/suite/setup.sh 21 | 22 | testSingleRequest() { 23 | # use local variables to avoid collision with other functions 24 | local FILENAME="$1" 25 | local ARGS="$2" 26 | local BEFORE_TEST_BASH="$3" 27 | local AFTER_TEST_BASH="$4" 28 | 29 | if [[ "$FILENAME" == "response-type-arg-overidden-decode-raw"* && "$(uname)" == *"MINGW"* ]]; then 30 | echo "🚧🚧🚧 SKIPPED 🚧🚧🚧 - $FILENAME skipped on Windows due to special circumstances." 31 | return 0 32 | fi 33 | 34 | EXPECTED="test/results/$FILENAME-expected.txt" 35 | OUT="test/results/$FILENAME-out.txt" 36 | OUT_ERR="test/results/$FILENAME-out-err-tmp.txt" 37 | touch "$EXPECTED" 38 | rm -f "$OUT" || true 39 | rm -f "$OUT_ERR" || true 40 | docker rm -f "$FILENAME" >/dev/null 2>&1 || true # stop any previously running container for this testcase 41 | EXIT_CODE="?" # default exit code, if process aborts abnormaly 42 | 43 | echo "######### STDOUT #########" >"$OUT" 44 | 45 | set +e 46 | 47 | if [[ "$BEFORE_TEST_BASH" == "" ]]; then BEFORE_TEST_BASH="true"; fi 48 | if [[ "$AFTER_TEST_BASH" == "" ]]; then AFTER_TEST_BASH="true"; fi 49 | 50 | eval "$RUN_CLIENT --entrypoint bash \ 51 | --name $FILENAME $PROTOCURL_IMAGE \ 52 | -c '$BEFORE_TEST_BASH && ./bin/protocurl $ARGS && $AFTER_TEST_BASH'" \ 53 | 2>"$OUT_ERR" >>"$OUT" 54 | EXIT_CODE="$?" 55 | 56 | echo "######### STDERR #########" >>"$OUT" 57 | cat "$OUT_ERR" >>"$OUT" 58 | 59 | echo "######### EXIT $EXIT_CODE #########" >>"$OUT" 60 | 61 | meaningfulDiff "$EXPECTED" "$OUT" >/dev/null 62 | 63 | if [[ "$?" != 0 ]]; then 64 | export TESTS_SUCCESS="false" 65 | echo "❌❌❌ FAILURE ❌❌❌ - $FILENAME" 66 | echo "=== Found difference between expected and actual output (ignoring $NORMALISED_ASPECTS) ===" 67 | meaningfulDiff "$EXPECTED" "$OUT" | sed 's/^/ /' 68 | echo "The actual output was saved into $OUT for inspection." 69 | else 70 | echo "✨✨✨ SUCCESS ✨✨✨ - $FILENAME" 71 | fi 72 | 73 | set -e 74 | 75 | rm -f "$OUT_ERR" || true 76 | } 77 | 78 | # A spec consists of potentially many single requests. 79 | testSingleSpec() { 80 | # use local variables to avoid collision with other functions 81 | local FILENAME="$1" 82 | local ARGS="$2" 83 | local BEFORE_TEST_BASH="$3" 84 | local AFTER_TEST_BASH="$4" 85 | 86 | testSingleRequest "$FILENAME" "$ARGS" "$BEFORE_TEST_BASH" "$AFTER_TEST_BASH" 87 | shift 4 88 | for extra_arg in "$@"; do 89 | local NEW_FILENAME="${FILENAME}-${extra_arg#--}" 90 | NEW_FILENAME="$(echo "$NEW_FILENAME" | sed 's/ /_/g' | sed 's/\./_/g')" # sanitise filename 91 | testSingleRequest "$NEW_FILENAME" "$extra_arg $ARGS" "$BEFORE_TEST_BASH" "$AFTER_TEST_BASH" 92 | done 93 | } 94 | 95 | runAllTests() { 96 | echo "=== Running ALL Tests ===" 97 | rm -f ./test/suite/run-testcases.sh || true 98 | 99 | # Convert each element in the JSON to the corresponding call of the testSingleRequest function. 100 | # Simply look at the produced run-testcases.sh file to see what it looks like. 101 | CONVERT_TESTCASE_TO_SINGLE_TEST_INVOCATION=".[] | \"testSingleSpec \(.filename|@sh) \(.args|join(\" \")|@sh) \(.beforeTestBash // \"\"|@sh) \(.afterTestBash // \"\"|@sh) \((.rerunwithArgForEachElement // [])|@sh)\"" 102 | cat test/suite/testcases.json \ 103 | | jq -r "$CONVERT_TESTCASE_TO_SINGLE_TEST_INVOCATION" \ 104 | >./test/suite/run-testcases.sh 105 | 106 | export -f testSingleSpec 107 | export -f testSingleRequest 108 | chmod +x ./test/suite/run-testcases.sh 109 | source ./test/suite/run-testcases.sh 110 | 111 | echo "=== Finished Running ALL Tests ===" 112 | } 113 | 114 | setup 115 | runAllTests 116 | tearDown 117 | 118 | eval "$TESTS_SUCCESS" 119 | --------------------------------------------------------------------------------