--- title: apifw integration tests ... # Introduction This is an integration test suite for the Python `apifw` module, using `yarn`. It starts a little test application, `apitest.py` using `gunicorn3` and verifies that it can do HTTP requests to it. It then kills the test application. Very simple, but it makes sure the interaction between `gunicorn3`, `bottle.py`, and the `apifw` module works correctly. `apifw` is short for "application programming interface framework". It's a silly name. Please suggest something better. # Basic scenario SCENARIO runs apitest OK GIVEN a running apitest using gunicorn3 WHEN client requests GET /version without token THEN HTTP status code is 200 OK WHEN client gets an authorization token with scope "no_version_scope" AND client requests GET /version using token THEN HTTP status code is 200 OK WHEN client gets an authorization token with scope "uapi_version_get" AND client requests GET /version using token THEN HTTP status code is 200 OK AND HTTP body is "version: 4.2" WHEN client gets an authorization token with scope "uapi_upload_put" AND client uploads a fake jpg THEN HTTP status code is 200 OK AND HTTP body is "thank you for your data" WHEN client gets an authorization token with scope "uapi_download_get" AND client requests GET /download using token THEN HTTP status code is 200 OK AND HTTP body is "fake jpg" FINALLY stop apitest # Step implementations IMPLEMENTS GIVEN a running apitest using gunicorn3 # Set the "aud" field for access tokens. export APITEST_AUD=test-audience echo "$APITEST_AUD" > "$DATADIR/aud" # Set the "iss" field for access tokens. export APITEST_ISS=test-issuer echo "$APITEST_ISS" > "$DATADIR/iss" # Generate an RSA key for signing access tokens for the API. Key # generation is disabled, to make test suite faster. Using # pre-generated key instead. #./generate-rsa-key "$DATADIR/signing-key" export APITEST_PUBKEY="$(cat "$SRCDIR/apitest.key.pub")" # FIXME: It would be good for the test suite to pick a random free # port. But that's not simple. export APITEST_LOG="$DATADIR/apitest.log" "$SRCDIR/randport" > "$DATADIR/port" port="$(cat "$DATADIR/port")" gunicorn3 --daemon --bind "127.0.0.1:$port" -p "$DATADIR/pid" \ --log-file "$DATADIR/log" --log-level=debug \ apitest:app while ! curl -s "http://127.0.0.1:$port/version" > /dev/null do # Sleep in Debian can take a fractional second arg. sleep 0.1 done IMPLEMENTS FINALLY stop apitest kill "$(cat "$DATADIR/pid")" IMPLEMENTS WHEN client requests GET /version without token port="$(cat "$DATADIR/port")" curl -sv "http://127.0.0.1:$port/version" > "$DATADIR/out" 2> "$DATADIR/err" IMPLEMENTS WHEN client requests GET /version using token token="$(cat "$DATADIR/token")" port="$(cat "$DATADIR/port")" curl -sv -H "Authorization: Bearer $token" \ "http://127.0.0.1:$port/version" > "$DATADIR/out" 2> "$DATADIR/err" IMPLEMENTS WHEN client requests GET /download using token token="$(cat "$DATADIR/token")" port="$(cat "$DATADIR/port")" curl -sv -H "Authorization: Bearer $token" \ "http://127.0.0.1:$port/download" > "$DATADIR/out" 2> "$DATADIR/err" IMPLEMENTS WHEN client uploads a fake jpg token="$(cat "$DATADIR/token")" port="$(cat "$DATADIR/port")" curl -sv -H "Authorization: Bearer $token" \ -H "Content-type: application/jpeg" \ -d "fake jpg" \ -X PUT \ "http://127.0.0.1:$port/upload" > "$DATADIR/out" 2> "$DATADIR/err" IMPLEMENTS WHEN client gets an authorization token with scope "(.+)" iss="$(cat "$DATADIR/iss")" aud="$(cat "$DATADIR/aud")" ./create-token "$SRCDIR/apitest.key" "$iss" "$aud" "$MATCH_1" > "$DATADIR/token" IMPLEMENTS THEN HTTP status code is (.+) cat "$DATADIR/err" tr -d '\r' < "$DATADIR/err" | grep -Fx "< HTTP/1.1 $MATCH_1" IMPLEMENTS THEN HTTP body is "(.+)" grep -Fx "$MATCH_1" "$DATADIR/out" IMPLEMENTS THEN response has header WWW-Authenticate containing "(.+)" cat "$DATADIR/err" tr -d '\r' < "$DATADIR/err" | grep -Fix "< WWW-Authenticate: $MATCH_1"