mirror of https://github.com/istio/istio.io.git
257 lines
9.4 KiB
Markdown
257 lines
9.4 KiB
Markdown
# Testing istio.io Content
|
|
|
|
This folder contains tests for the content on [istio.io](http://istio.io).
|
|
More specifically, these tests confirm that the example and task 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).
|
|
|
|
## Test Authoring Overview
|
|
|
|
To write an `istio.io` test, follow these steps:
|
|
|
|
1. Add a field `test: true` to the metadata at the top of the `index.md` file to be tested.
|
|
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()`.
|
|
|
|
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 `snip.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 in the `index.md` file and
|
|
then regenerate the snips.
|
|
|
|
1. Pick an appropriate location under the `tests/` directory and create a directory for your new
|
|
test.
|
|
|
|
1. Add the following imports to your GoLang file:
|
|
|
|
```golang
|
|
"istio.io/istio/pkg/test/framework"
|
|
"istio.io/istio/pkg/test/framework/components/environment"
|
|
"istio.io/istio/pkg/test/framework/components/istio"
|
|
|
|
"istio.io/istio.io/pkg/test/istioio"
|
|
```
|
|
|
|
1. Create a function called `TestMain`, following the example below. This
|
|
function sets up the Istio environment that the test uses. The `Setup`
|
|
function accepts an optional function to customize the Istio environment
|
|
deployed.
|
|
|
|
```golang
|
|
func TestMain(m *testing.M) {
|
|
framework.NewSuite("my-istioio-test", m).
|
|
SetupOnEnv(environment.Kube, istio.Setup(&ist, nil)).
|
|
RequireEnvironment(environment.Kube).
|
|
Run()
|
|
}
|
|
```
|
|
|
|
1. To create a test, you use `istioio.NewBuilder` to build a series of steps that will
|
|
be run as part of the resulting test function:
|
|
|
|
```golang
|
|
func TestCombinedMethods(t *testing.T) {
|
|
framework.
|
|
NewTest(t).
|
|
Run(istioio.NewBuilder("tasks__security__my_task").
|
|
Add(istioio.Script{
|
|
Input: istioio.Path("myscript.sh"),
|
|
},
|
|
istioio.MultiPodWait("foo"),
|
|
istioio.Script{
|
|
Input: istioio.Path("myotherscript.sh"),
|
|
}).Build())
|
|
}
|
|
```
|
|
|
|
## Running Shell Commands
|
|
|
|
Your test will include one or more test steps that run shell scripts that call
|
|
the commands in the generated `snips.sh` file.
|
|
|
|
```golang
|
|
istioio.Script{
|
|
Input: istioio.Path("myscript.sh"),
|
|
}
|
|
```
|
|
|
|
Your script must include the `snip.sh` file for the document being tested. For example,
|
|
a test for the traffic-shifting task will have the following line in the script:
|
|
|
|
```sh
|
|
source ${REPO_ROOT}/content/en/docs/tasks/traffic-management/traffic-shifting/snips.sh
|
|
```
|
|
|
|
Your test script can then 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 that needs to be verified, capture the command output
|
|
in a variable and compare it to the expected output. For example:
|
|
|
|
```sh
|
|
out=$(snip_set_up_the_cluster_3 2>&1)
|
|
_verify_same "$out" "$snip_set_up_the_cluster_3_out" "snip_set_up_the_cluster_3"
|
|
```
|
|
|
|
The framework includes the following built-in verify functions:
|
|
|
|
1. **`_verify_same`** `out` `expected` `msg`
|
|
|
|
Verify that `out` is exactly the same as `expected`. Failure messages will include
|
|
the specified `msg`.
|
|
|
|
1. **`_verify_contains`** `out` `expected` `msg`
|
|
|
|
Verify that `out` contains the substring `expected`. Failure messages will include
|
|
the specified `msg`.
|
|
|
|
1. **`_verify_like`** `out` `expected` `msg`
|
|
|
|
Verify that `out` is "like" `expected`. 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`)
|
|
1. prefix match ending with a dash character (e.g., `reviews-v1-12345...` is like `reviews-v1-67890...`)
|
|
|
|
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.
|
|
|
|
## Builder
|
|
|
|
The `istioio.NewBuilder` returns a `istioio.Builder` that is used to build an Istio
|
|
test run function and has the following methods:
|
|
|
|
- `Add`: adds a step to the test.
|
|
- `Defer`: provides a step to be run after the test completes.
|
|
- `Build`: builds an Istio test run function.
|
|
|
|
## Selecting Input
|
|
|
|
Many test steps require an `Input` which they obtain from an
|
|
`istioio.InputSelector`:
|
|
|
|
```golang
|
|
type Input interface {
|
|
InputSelector
|
|
Name() string
|
|
ReadAll() (string, error)
|
|
}
|
|
|
|
type InputSelector interface {
|
|
SelectInput(Context) Input
|
|
}
|
|
```
|
|
|
|
Some common `InputSelector` implementations include:
|
|
|
|
- `istioio.Inline`: allows you to inline the content for the `Input` directly in the code.
|
|
- `istioio.Path`: reads in a file from the specified path.
|
|
- `istioio.BookInfo`: is like `istioio.Path` except that the value is assumed to be
|
|
relative to the BookInfo source directory (`$GOPATH/src/istio.io/istio/samples/bookinfo/platform/kube/`).
|
|
|
|
An `InputSelector` provides an `istioio.Context` at runtime, which it can use to
|
|
dynamically choose an `Input`. For example, we could choose a different file depending on
|
|
whether or not the test is running on Minikube:
|
|
|
|
```golang
|
|
istioio.InputSelectorFunc(func(ctx istioio.Context) Input {
|
|
if ctx.Env.Settings().Minikube {
|
|
return istioio.Path("scripts/curl-httpbin-tls-gateway-minikube.sh")
|
|
}
|
|
return istioio.Path("scripts/curl-httpbin-tls-gateway-gke.sh")
|
|
})
|
|
```
|
|
|
|
The library also provides a utility that helps simplify this particular use case:
|
|
|
|
```golang
|
|
istioio.IfMinikube{
|
|
Then: istioio.Path("scripts/curl-httpbin-tls-gateway-minikube.sh")
|
|
Else: istioio.Path("scripts/curl-httpbin-tls-gateway-gke.sh")
|
|
}
|
|
```
|
|
|
|
## Waiting for Pods to Start
|
|
|
|
You can create a test step that waits for one or more pods to start before continuing.
|
|
For example, to wait for all pods in the "foo" namespace, you can do the following:
|
|
|
|
```golang
|
|
istioio.MultiPodWait("foo"),
|
|
```
|
|
|
|
## Running the Tests: Make
|
|
|
|
You can execute all istio.io tests using make.
|
|
|
|
```bash
|
|
export KUBECONFIG=~/.kube/config
|
|
make test.kube.presubmit
|
|
```
|
|
|
|
### Notes:
|
|
|
|
There is an issue with the TAG (#7081) so one needs to set TAG to `latest` to mimic the
|
|
pipeline.
|
|
|
|
In the case of using `kind` clusters on the Mac, an extra env var is needed,
|
|
ADDITIONAL_CONTAINER_OPTIONS="--network host". If one makes sure HUB is not set, then the
|
|
command `TEST_ENV=kind ADDITIONAL_CONTAINER_OPTIONS="--network host" make test.kube.presubmit`
|
|
has been successful.
|
|
|
|
## Running Tests: go test
|
|
|
|
You can execute individual tests using Go test as shown below.
|
|
|
|
```bash
|
|
make init
|
|
export REPO_ROOT=$(git rev-parse --show-toplevel)
|
|
go test ./tests/... -p 1 --istio.test.env kube \
|
|
--istio.test.ci --istio.test.work_dir <my_dir>
|
|
```
|
|
|
|
The value of `my_dir` will be the parent directory for your test output. Within
|
|
`my_dir`, each test `Main` will create a directory containing a subdirectory for
|
|
each test method. Each test method directory will contain a `snippet.txt` that
|
|
was generated for that particular test.
|
|
|
|
Make sure to have the `HUB` and `TAG` [environment variables set](https://github.com/istio/istio/wiki/Preparing-for-Development#setting-up-environment-variables) to the location of
|
|
your Istio Docker images.
|
|
|
|
You can find the complete list of arguments on [the test framework wiki page](https://github.com/istio/istio/wiki/Istio-Test-Framework).
|