Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,6 @@ cython_debug/
allure_reports/
cucumber_reports/
reports/
allure-report/
allure_results/

.target_project
dump/
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install
You also need to have **Docker running** since the tests are run inside a docker container.


## Quick start
## Quick start
In order to get started, we set up an [example composition for a service account](test/pkg/service-account-with-functions/composition.yaml) inside the `test` folder.

The composition will create the following resources:
Expand All @@ -49,11 +49,9 @@ of the scenario or the feature (like "minor" or "critical") are specific to test

**Note**: IDEs like Pycharm have a built-in support for behave and other BDD frameworks will allow you to run the tests directly from the IDE.

## Tests runner

You can also use our custom `tests_runner.sh` script, that runs the tests against a target folder with feature files and generates cucumber and allure reports that you can view in your CI tool.
```bash
./tests_runner.sh test
./tests_runner.sh test/composition-tests
```
Here is an example output with the Jenkins allure plugin

Expand Down
10 changes: 5 additions & 5 deletions docs/how_it_works.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ Under the hood, tests run the crossplane `render` command with the given inputs
It then compares the rendered output with the expected output.
In that sense, this tool is a wrapper around the crossplane `render` command.

The [crossplane CLI render command]((https://docs.crossplane.io/latest/concepts/composition-functions/#test-a-composition-that-uses-functions).) accompanied the composition functions feature in the v1.14 Crossplane release. It's used to render locally
your compositions given a claim. The output is what is usually passed on to the providers if the composition ran in a real cluster. It takes in the composition, the claim for that composition and the composition functions as inputs.
The [crossplane CLI render command](https://docs.crossplane.io/latest/cli/command-reference/#render) accompanied the composition functions feature in the v1.14 Crossplane release. It's used to render locally
your compositions given an input *composite resource* (or a *claim* in v1 Crossplane). The output is what is usually passed on to the providers if the composition ran in a real cluster. It takes in the composition, the xr for that composition and the composition functions as inputs.
```bash
crossplane beta render claim.yaml composition.yaml functions.yaml
crossplane beta render xr.yaml composition.yaml functions.yaml
```

Some compositions are deterministic and will always render the same output given the same inputs. However, **compositions
are usually non-deterministic and will give different outputs depending on the current observed state**. This reflects
what happens when you run the composition in a real cluster. This can occur for instance when the resources depend on some input from the claim or if there are dependencies between managed resources. For example,
what happens when you run the composition in a real cluster. This can occur for instance when the resources depend on some input from the xr or if there are dependencies between managed resources. For example,
in the [service account composition](test/pkg/service-account-with-functions/composition.yaml) , a `RolePolicyAttachment` resource object cannot be created until the `Role` and `Policy` resource objects have been created.

To emulate this behavior, the crossplane `render` command also takes an additional optional argument, the **observed state**.
```bash
crossplane beta render claim.yaml composition.yaml functions.yaml -o observed.yaml
crossplane beta render xr.yaml composition.yaml functions.yaml -o observed.yaml
```

The observed state is a yaml file that contains the list of resources that are or already have been provisioned.
Expand Down
17 changes: 11 additions & 6 deletions environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from behave import fixture, use_fixture
from behave.runner import Context

COMPOSITION_TESTER_FUNCTIONS_FILE_ON_CI = "COMPOSITION_TESTER_FUNCTIONS_FILE"

@fixture
def setup_base_path(ctx: Context, feature):
"""Retrieve the base path for the feature file. The base path is the path to the
Expand Down Expand Up @@ -87,11 +89,11 @@ def setup_functions_filepath(ctx: Context):
# By default, functions files are stored in the same directory as the features
ctx.functions_folder_path = all_features_directory
if on_ci():
print("Running on CI!")
# print("Running on CI!")
ctx.on_ci = True
# If running on CI, the default functions file is specified by the environment variable "COMPOSITION_TESTER_FUNCTIONS_FILE"
ci_functions_file = os.environ[
"COMPOSITION_TESTER_FUNCTIONS_FILE"
COMPOSITION_TESTER_FUNCTIONS_FILE_ON_CI
] # e.g. "functions-ci.yaml"
functions_filepath = all_features_directory / ci_functions_file
else:
Expand All @@ -106,9 +108,9 @@ def setup_functions_filepath(ctx: Context):

@fixture
def setup_composition_filepath(ctx: Context):
"""Setup the composition path of the current feature and save it in the context. By convention, the compositions
"""Setup the composition and definition path of the current feature and save it in the context. By convention, the compositions
directory should be in the "pkg" folder at the root of the project. Also by convention the file is named
"composition.yaml"
"composition.yaml" and "definition.yaml".

Example:
├── composition-tests
Expand All @@ -122,8 +124,10 @@ def setup_composition_filepath(ctx: Context):
├── pkg # Compositions directory
├── feature 1
├── composition.yaml
├── definition.yaml
├── feature 2
├── composition.yaml
├── definition.yaml
"""
# For example, "feature-1"
feature_directory_name = ctx.base_path.name
Expand All @@ -134,6 +138,7 @@ def setup_composition_filepath(ctx: Context):
ctx.compositions_directory = compositions_directory
# For example "/pkg/feature-1/composition.yaml"
ctx.composition_filepath = compositions_directory / "composition.yaml"
ctx.definition_filepath = compositions_directory / "definition.yaml"

@fixture
def setup_from_environment(ctx: Context):
Expand All @@ -153,7 +158,7 @@ def before_feature(context, feature):

def on_ci():
# check special environment variable to determine if running locally or in CI pipeline (e.g. GITLAB_CI)
return "COMPOSITION_TESTER_FUNCTIONS_FILE" in os.environ
return COMPOSITION_TESTER_FUNCTIONS_FILE_ON_CI in os.environ

def before_scenario(context: Context, scenario):
"""
Expand Down Expand Up @@ -181,4 +186,4 @@ def after_scenario(context: Context, scenario):
cleanup. Otherwise, nothing happens.
"""
if context.debug_mode and context.execution_folder:
print(f"DEBUG MODE ON - Scenario '{scenario.name}' dumps stored in: {context.execution_folder}")
print(f"DEBUG MODE ON - Scenario '{scenario.name}' dumps stored in: {context.execution_folder}")
7 changes: 0 additions & 7 deletions examples/test/composition-tests/envconfig.yaml

This file was deleted.

This file was deleted.

This file was deleted.

Loading