curl

The atago project wrote these specs on its own initiative and runs them in its own CI, to exercise atago against a real program. They are not curl’s official test suite, and the curl project is not affiliated with atago.

Summary #

1 suite · 13 scenarios

Contents #

curl (what actually goes on the wire) #

Every flag of curl that shapes a request is a promise about bytes a server will receive, and the one place that promise can be checked is at the server. These scenarios declare an atago mock server, run curl against it, and then assert the recorded request — its method, its headers, its body, and how many of them there were.

What curl prints is asserted only where the transfer itself is the subject — the body of a response, a status code asked for with -w, a timeout. The flags that shape a request are checked at the server, because that is the only place they show: -d and --data-binary differ in what is sent, not in what is displayed, and -X GET with a body is a request no output would warn you about.

No network is reached: the server is atago’s own, on a loopback port that only lives as long as the scenario.

Source: test/e2e/thirdparty/curl/requests.atago.yaml

Scenario: a plain GET is a GET, with the headers curl adds on its own #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s ${api.url}/hello

Then #

  • exit code is 0
  • stdout equals an exact value
  • mock api received GET /hello exactly 1 time(s)
  • mock api received /hello
  • mock api received /hello

Expected output #

expected stdout:

hi

Scenario: -d makes it a POST and names the form encoding #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -d name=ada -d role=engineer ${api.url}/submit

Then #

  • exit code is 0
  • mock api received POST /submit exactly 1 time(s)
  • mock api received /submit

Scenario: -d strips the newlines that –data-binary keeps #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Fixture file payload.txt is created.
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

Inputs #

Fixture payload.txt:

first line
second line

When #

curl -s -d @payload.txt ${api.url}/upload
curl -s --data-binary @payload.txt ${api.url}/upload

Then #

  • after curl -s -d @payload.txt ${api.url}/upload:
    • exit code is 0
    • mock api received POST /upload
  • after curl -s --data-binary @payload.txt ${api.url}/upload:
    • exit code is 0
    • mock api received POST /upload

Scenario: –json sets both content types and sends the body untouched #

only when curl --help all | grep -q -- --json succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Fixture file item.json is created.
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

Inputs #

Fixture item.json:

{"name": "ada", "tags": ["a", "b"]}

When #

curl -s --json @item.json ${api.url}/v1/items

Then #

  • exit code is 0
  • mock api received POST /v1/items exactly 1 time(s)
  • mock api received /v1/items
  • mock api received /v1/items

Scenario: -F builds a multipart body with a boundary in the header #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Fixture file note.txt is created.
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

Inputs #

Fixture note.txt:

the file content

When #

curl -s -F title=a-note -F file=@note.txt ${api.url}/files

Then #

  • exit code is 0
  • mock api received POST /files
  • mock api received /files

Scenario: -H replaces a header curl would have sent, and can delete one #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -H "User-Agent: atago-suite/1.0" ${api.url}/hello
curl -s -H "Accept:" ${api.url}/hello

Then #

  • after curl -s -H "User-Agent: atago-suite/1.0" ${api.url}/hello:
    • exit code is 0
    • mock api received /hello
  • after curl -s -H "Accept:" ${api.url}/hello:
    • exit code is 0
    • mock api received /hello

Scenario: -u builds the Authorization header #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Fixture file credential.txt is created.
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

Inputs #

Fixture credential.txt:

ada:test-password

When #

curl -s -u "$(cat credential.txt)" ${api.url}/private

Then #

  • exit code is 0
  • mock api received GET /private exactly 1 time(s)

Scenario: -X renames the method and changes nothing else #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -X GET -d name=ada ${api.url}/odd

Then #

  • exit code is 0
  • mock api received GET /odd exactly 1 time(s)
  • mock api received /odd

Scenario: -G moves the data into the query string and leaves no body #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -G -d q=ada -d limit=10 ${api.url}/search

Then #

  • exit code is 0
  • mock api received GET /search exactly 1 time(s)

Scenario: -L follows the redirect, and the server sees both requests #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 2 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -d name=ada ${api.url}/old
curl -s -L -d name=ada ${api.url}/old

Then #

  • after curl -s -d name=ada ${api.url}/old:
    • exit code is 0
    • stdout is empty
    • mock api received /old exactly 1 time(s)
  • after curl -s -L -d name=ada ${api.url}/old:
    • exit code is 0
    • stdout equals an exact value
    • mock api received GET /new exactly 1 time(s)

Expected output #

expected stdout:

moved here

Scenario: a path the server does not serve is a 404 that curl reports only when asked #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s -o /dev/null -w "%{http_code}" ${api.url}/nowhere
curl -s -f -o /dev/null ${api.url}/nowhere

Then #

  • after curl -s -o /dev/null -w "%{http_code}" ${api.url}/nowhere:
    • exit code is 0
    • stdout equals an exact value
  • after curl -s -f -o /dev/null ${api.url}/nowhere:
    • exit code is 22
    • mock api received /nowhere exactly 2 time(s)

Scenario: a slow route is a timeout with its own exit code #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s --max-time 1 ${api.url}/slow

Then #

  • exit code is 28
  • stdout is empty

Scenario: the same request twice produces the same bytes #

only when curl --version succeeds · skipped on Windows

Given #

  • Stub HTTP server api serves 1 canned route(s) at ${api.url} and records every request (#24).
  • Environment variables are set: LC_ALL.
  • The command runs with an isolated home under ${workdir}/.atago-home (HOME/XDG or APPDATA redirected).

When #

curl -s ${api.url}/v1/item

Then #

  • exit code is 0
  • stdout at $.name equals ada
  • mock api received /v1/item exactly 3 time(s)