mirror of https://github.com/istio/istio.io.git
331 lines
15 KiB
Markdown
331 lines
15 KiB
Markdown
# Testing istio.io Content
|
|
|
|
This folder contains framework utilies and instructions for testing the content on
|
|
[istio.io](https://istio.io). More specifically, these tests confirm that the example, task, and
|
|
other documents, which contain instructions in the form of bash commands and expected output,
|
|
are working as documented.
|
|
|
|
Generated bash scripts, containing the set of commands and expected output for corresponding
|
|
istio.io markdown files, are used by test programs to invoke the commands and verify the output.
|
|
This means that we extract and test the exact same commands that are published in the documents.
|
|
|
|
These tests use the framework defined in the `istioio` package, which is a thin wrapper
|
|
around the [Istio test framework](https://github.com/istio/istio/wiki/Istio-Test-Framework).
|
|
|
|
Run the following command to see the current test coverage, including the list of tested documents
|
|
and those that are in need of a test:
|
|
|
|
```sh
|
|
make test_status
|
|
```
|
|
|
|
## Test Authoring Overview
|
|
|
|
To write an `istio.io` test, follow these steps:
|
|
|
|
1. In the metadata at the top of the `index.md` file to be tested, change the field `test: no` to
|
|
`test: yes`. This field is used to indicate that the markdown file will be tested and therefore
|
|
requires a generated bash script containing the commands described in the document.
|
|
|
|
1. Run `make snips` to generate the bash script. After the command completes, you should see
|
|
a new file, `snips.sh`, next to the `index.md` file that you modified in the previous step.
|
|
|
|
Each bash command in `index.md` (i.e., `{{< text bash >}}` code block) will produce a bash
|
|
function in `snips.sh` containing the same command(s) as in the document. Other types of code blocks,
|
|
e.g., `{{< text yaml >}}`, will produce a bash variable containing the block content.
|
|
|
|
By default, the bash function or variable will be named `snip_<section>_<code block number>`.
|
|
For example, the first `{{< text bash >}}` code block in a section titled
|
|
`## Apply weight-based routing` will generate a bash function named `snip_apply_weightbased_routing_1()`.
|
|
|
|
You can override the default name by adding `snip_id=<some name>` to the corresponding text block attributes.
|
|
For example `{{< text syntax=bash snip_id=config_all_v1 >}}` will generate `snip_config_all_v1()`.
|
|
|
|
> You can also entirely supress generation of a snip function by setting `snip_id=none`. This is useful for
|
|
> commands that are not intended to be directly executable (e.g., `kubectl get pod <your pod name>`) and are
|
|
> causing lint errors (see next step, below).
|
|
|
|
If a bash code block contains both commands and output, the `snips.sh` script will include
|
|
both a bash function and a variable containing the expected output. The name of the variable
|
|
will be the same as the function, only with `_out` appended.
|
|
|
|
1. Run `make lint-fast` to check for script errors.
|
|
|
|
If there are any lint errors in the generated `snips.sh` file,
|
|
it means that a command in the `index.md` file is not following `bash` best practices.
|
|
Because we are extracting the commands from the markdown file into a script file, we get the
|
|
added benefit of lint checking of the commands that appear in the docs.
|
|
|
|
Fix the errors, if any, by updating the corresponding command (or set `snip_id=none`) in the `index.md`
|
|
file and then regenerate the snips.
|
|
|
|
1. Create a test bash script named `test.sh` next to the `snips.sh` you have just generated.
|
|
|
|
If your document is very large and you want to break it into multiple tests, create multiple scripts with
|
|
the suffix `test.sh` (e.g., `part1_test.sh`, `part2_test.sh`), instead.
|
|
|
|
Other scripts in the directory will be ignored.
|
|
|
|
## Test Bash Script
|
|
|
|
Your bash script will consist of a series of test steps that call the commands in your
|
|
generated `snips.sh` file.
|
|
|
|
Your script can invoke the commands by simply calling snip functions:
|
|
|
|
```sh
|
|
snip_config_50_v3 # Step 3: switch 50% traffic to v3
|
|
```
|
|
|
|
For commands that produce output, pass the snip and expected output to an appropriate
|
|
`_verify_` function. For example:
|
|
|
|
```sh
|
|
_verify_same snip_set_up_the_cluster_3 "$snip_set_up_the_cluster_3_out"
|
|
```
|
|
|
|
This will run the function `snip_set_up_the_cluster_3` and confirm that the output is exactly
|
|
the same as specified in the variable `snip_set_up_the_cluster_3_out`.
|
|
|
|
Snip functions often update Istio configuration (e.g., virtual services, destination rules, etc.).
|
|
Use the `_wait_for_istio` function to allow the change to propogate to the Istio sidecars
|
|
before proceeding with the next step of the test:
|
|
|
|
```sh
|
|
snip_config_50_v3 # Step 3: switch 50% traffic to v3
|
|
_wait_for_istio virtualservice default reviews # wait for routing change to propagate
|
|
```
|
|
|
|
For snips that deploy Kubernetes services (e.g., `kubectl apply -f samples/httpbin/httpbin.yaml`),
|
|
use the `_wait_for_deployment` function to wait for the deployment to roll out:
|
|
|
|
```sh
|
|
_wait_for_deployment default httpbin
|
|
```
|
|
|
|
You can also use this function to wait for installation changes resulting from `istioctl install` commands:
|
|
|
|
```sh
|
|
_wait_for_deployment istio-system istiod
|
|
```
|
|
|
|
### Test Setup and Cleanup
|
|
|
|
Before the test steps, there must be one line that specifies the istio setup configuration for the test:
|
|
|
|
```sh
|
|
# @setup <setup_config>
|
|
```
|
|
|
|
Currently supported setup configurations include: `profile=default` to install the default profile,
|
|
`profile=demo` to install the demo profile, `profile=ambient` to install the ambient profile,
|
|
and `profile=none` to not install istio at all.
|
|
|
|
Choose the setup configuration that best matches the document prerequisites. For example, if the
|
|
document being tested includes snips with explicit install commands (e.g., setup docs), use:
|
|
|
|
```sh
|
|
# @setup profile=none
|
|
```
|
|
|
|
This will start the test using a clean Kubernetes cluster without Istio installed.
|
|
|
|
If, on the other hand, the doc's `Before you begin` section refers the user to the standard
|
|
Istio installation instructions, chose the profile specified in the doc or `default` if there is
|
|
no specific profile mentioned in the instructions.
|
|
|
|
After all test steps are complete, add the following line to indicate the start of the cleanup steps:
|
|
|
|
```sh
|
|
# @cleanup
|
|
```
|
|
All steps after this line will be run by the framework, even if the test fails and prematurely exits.
|
|
The cleanup steps must remove all resources and reverse configuration changes made during the test steps.
|
|
|
|
Many documents have cleanup instuctions in them, so simply calling the cleanup snip functions will usually
|
|
reverse all changes made during the test steps. However, extra care should be taken to ensure that the
|
|
cleanup steps are complete so that after running them, the cluster will be left in the exact same state
|
|
that it started in. This is important because the test framework runs all tests that specify the
|
|
same `# @setup` using the same Kubernetes cluster, so any remaining config changes after the cleanup
|
|
steps are run, will potentially break a following test.
|
|
|
|
> The framework compares the before and after cluster state and will fail tests that it
|
|
> detects are not properly cleaning up. This comparison, however, is currently not a complete
|
|
> verification, so tests that pass this check may still not be cleaning up completely.
|
|
|
|
### Include Files
|
|
|
|
The framework automatically includes several bash scripts into your `test.sh` file, so you
|
|
don't have to `source` them yourself. This includes your generated `snips.sh` file as well
|
|
as some scripts containing framework utility functions:
|
|
|
|
* [tests/util/verify.sh](./util/verify.sh)
|
|
* [tests/util/helpers.sh](./util/helpers.sh)
|
|
|
|
You can directly call any function defined in them.
|
|
|
|
Other optional include files need to be explicitly sourced.
|
|
For example, tests that use the standard Istio sample services, will typically want to leverage
|
|
some of the functions in [tests/util/samples.sh](./util/samples.sh):
|
|
|
|
```sh
|
|
source "tests/util/samples.sh"
|
|
|
|
startup_bookinfo_sample # from tests/util/samples.sh
|
|
snip_config_50_v3 # from ./snips.sh
|
|
```
|
|
|
|
### Verify Functions
|
|
|
|
The verify functions first run the snip function and then compare the result to the
|
|
expected output. The framework includes the following built-in verify functions:
|
|
|
|
1. **`_verify_same`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If they are not the same,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
1. **`_verify_contains`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If the output does not
|
|
contain the substring `expected`,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
1. **`_verify_not_contains`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If the command execution fails
|
|
or the output contains the substring `expected`,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
1. **`_verify_elided`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If the output does not
|
|
contain the lines in `expected` where "..." on a line matches one or more lines
|
|
containing any text,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
1. **`_verify_regex`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with the regex string `expected`. If the output
|
|
does not match with the regex string `expected`,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
1. **`_verify_like`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If the output is not
|
|
"like" `expected`,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
Like implies:
|
|
|
|
- Same number of lines
|
|
- Same number of whitespace-seperated tokens per line
|
|
- Tokens can only differ in the following ways:
|
|
|
|
1. different elapsed time values (e.g., `30s` is like `5m`)
|
|
1. different ip values (e.g., `172.21.0.1` is like `10.0.0.31`). Disallows
|
|
`<none>` and `<pending>` by default. This can be customized by setting
|
|
the `CMP_MATCH_IP_NONE` and `CMP_MATCH_IP_PENDING` environment variables,
|
|
respectively.
|
|
1. prefix match ending with a dash character (e.g., `reviews-v1-12345...` is like `reviews-v1-67890...`)
|
|
1. expected `...` is a wildcard token, matches anything
|
|
1. different dates in YYYY-MM-DD (e.g. 2024-04-17)
|
|
1. different times in HH:MM:SS.MS (e.g. 22:14:45.964722028)
|
|
|
|
This function is useful for comparing the output of commands that include some run-specific
|
|
values in the output (e.g., `kubectl get pods`), or when whitespace in the output may be different.
|
|
|
|
1. **`_verify_lines`** `func` `expected`
|
|
|
|
Runs `func` and compares the output with `expected`. If the output does not
|
|
"conform to" the specification in `expected`,
|
|
wait a second and try again, up to two minutes by default. The retry behavior
|
|
can be changed by setting the `VERIFY_TIMEOUT` and `VERIFY_DELAY` environment
|
|
variables. You can also specify the expected number of consecutive successes
|
|
by setting the `VERIFY_CONSECUTIVE` environment variable.
|
|
|
|
Conformance implies:
|
|
|
|
1. For each line in `expected` with the prefix "+ " there must be at least one
|
|
line in the output containing the following string.
|
|
1. For each line in `expected` with the prefix "- " there must be no line in
|
|
the output containing the following string.
|
|
|
|
1. **`_verify_failure`** `func`
|
|
|
|
Runs `func` and confirms that it fails (i.e., non-zero return code). This function is useful
|
|
for testing commands that demonstrate configurations that are expected to fail.
|
|
|
|
## Running the Tests
|
|
|
|
The following command will run all the doc tests within a `kube` environment:
|
|
|
|
```bash
|
|
make doc.test
|
|
```
|
|
|
|
The `make doc.test` target can be passed two optional environment variables: `TEST` and `TIMEOUT`.
|
|
|
|
`TEST` specifies a directory relative to `content/en/docs/` containing the tests to run.
|
|
For example, the following command will only run the tests under `content/en/docs/tasks/traffic-management`:
|
|
|
|
```bash
|
|
make doc.test TEST=tasks/traffic-management
|
|
```
|
|
|
|
You can also run one or more individual test by listing the full test names separated by commas. For example:
|
|
|
|
```bash
|
|
make doc.test TEST=tasks/traffic-management/request-routing,tasks/traffic-management/fault-injection
|
|
```
|
|
|
|
`TIMEOUT` specifies a time limit exceeding which all tests will halt, and the default value is 30 minutes (`30m`).
|
|
|
|
You can also find this information by running `make doc.test.help`.
|
|
|
|
### Notes
|
|
|
|
1. The [tests/util/debug.sh](./util/debug.sh) script is automatically included in every `test.sh` script
|
|
to enable bash tracing. The bash tracing output can be found in `out/<test_path>_[test|cleanup]_debug.txt`.
|
|
|
|
1. When using `kind` clusters, you may notice a `Exiting due to setup failure: failed waiting for istio-eastwestgateway to become ready: timeout while waiting`
|
|
error as the Istio control plane is being started. Adding a config when creating your `kind` cluster should fix the issue:
|
|
|
|
```sh
|
|
kind create cluster --name istio-test --config prow/config/default.yaml
|
|
```
|
|
|
|
1. When using `kind` clusters on a Mac, an extra env var is needed (ADDITIONAL_CONTAINER_OPTIONS="--network host").
|
|
Use the following command:
|
|
|
|
```sh
|
|
TEST_ENV=kind ADDITIONAL_CONTAINER_OPTIONS="--network host" make doc.test
|
|
```
|
|
|
|
If you encounter `couldn't get current server API group list: Get "...": dial tcp ... connect: connection refused`, the option above also works.
|
|
|
|
1. Set the HUB and TAG environment variables to use a particular Istio build when running tests.
|
|
If unset, their default values will match those used by the prow tests.
|
|
|
|
1. For help debugging, you can enable script output to the `stdout` with the command-line flag
|
|
`--log_output_level=script:debug`. This is useful when you're running in an IDE and don't
|
|
want to find and tail the test output files.
|