diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index edf52a6..9366341 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -57,3 +57,27 @@ jobs: - name: Execute tests in the running services run: | make -f ./e2e/missing-cluster/Makefile test + parallel-requests: + name: Parallel requests integration test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + target: wasm32-unknown-unknown + - uses: arduino/setup-protoc@v1 + with: + version: '3.x' + - uses: actions-rs/cargo@v1 + with: + command: build + args: --target wasm32-unknown-unknown + - name: Run docker compose + run: | + docker compose -f ./e2e/parallel-requests/docker-compose.yaml run start_services + - name: Execute tests in the running services + run: | + make -f ./e2e/parallel-requests/Makefile test diff --git a/e2e/parallel-requests/Makefile b/e2e/parallel-requests/Makefile new file mode 100644 index 0000000..c3a8b8f --- /dev/null +++ b/e2e/parallel-requests/Makefile @@ -0,0 +1,17 @@ +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec +.DEFAULT_GOAL := gateway +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +WORKDIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) +DOCKER ?= $(shell which docker 2> /dev/null || echo "docker") + +run: + $(DOCKER) compose -f docker-compose.yaml run start_services + +test: + $(WORKDIR)/run-parallel-requests.sh + + +clean: + $(DOCKER) compose down --volumes --remove-orphans + $(DOCKER) compose -f docker-compose.yaml down --volumes --remove-orphans diff --git a/e2e/parallel-requests/README.md b/e2e/parallel-requests/README.md new file mode 100644 index 0000000..9535087 --- /dev/null +++ b/e2e/parallel-requests/README.md @@ -0,0 +1,66 @@ +## Parallel requests integration test + +This is a integration test to validate when envoy receives multiple parallel requests. + +This test is being added to the CI test suite + +### Description + +The Wasm configuration defines a set of rules for `*.example.com` + +```json +"services": { + "limitador": { + "type": "ratelimit", + "endpoint": "limitador", + "failureMode": "deny" + } +}, +"actionSets": [ +{ + "actions": [ + { + "service": "limitador", + "scope": "b", + "data": [ + { + "expression": { + "key": "limit_to_be_activated", + "value": "1" + } + } + ] + } + ] +} +] +``` + +Check Envoy logs: + +``` +docker compose logs -f envoy +``` + +The test will run multiple requests in parallel and expect all of them to succeed. + +### Run Manually + +It requires Wasm module being built at `target/wasm32-unknown-unknown/debug/wasm_shim.wasm`. +Check *Makefile* at the root of the project to build the module. + +``` +make run +``` + +Run the test + +``` +make test +``` + +### Clean up + +``` +make clean +``` diff --git a/e2e/parallel-requests/docker-compose.yaml b/e2e/parallel-requests/docker-compose.yaml new file mode 100644 index 0000000..bcecea7 --- /dev/null +++ b/e2e/parallel-requests/docker-compose.yaml @@ -0,0 +1,56 @@ +--- +services: + envoy: + image: envoyproxy/envoy:v1.31-latest + depends_on: + - limitador + - upstream + command: + - /usr/local/bin/envoy + - --config-path + - /etc/envoy.yaml + - --log-level + - info + - --component-log-level + - wasm:debug,http:debug,router:debug + - --service-cluster + - proxy + expose: + - "80" + - "8001" + ports: + - "18000:80" + - "18001:8001" + volumes: + - ./envoy.yaml:/etc/envoy.yaml + - ../../target/wasm32-unknown-unknown/debug/wasm_shim.wasm:/opt/kuadrant/wasm/wasm_shim.wasm + limitador: + image: quay.io/kuadrant/limitador:latest + command: ["limitador-server", "-vvv", "/opt/kuadrant/limits/limits.yaml"] + ports: + - "18080:8080" + - "18081:8081" + expose: + - "8080" + - "8081" + volumes: + - ./limits.yaml:/opt/kuadrant/limits/limits.yaml + upstream: + image: quay.io/kuadrant/authorino-examples:talker-api + environment: + PORT: 3000 + expose: + - "3000" + start_services: + image: alpine + depends_on: + - envoy + command: > + /bin/sh -c " + while ! nc -z envoy 80; + do + echo sleeping; + sleep 1; + done; + echo Connected! + " diff --git a/e2e/parallel-requests/envoy.yaml b/e2e/parallel-requests/envoy.yaml new file mode 100644 index 0000000..94d7a94 --- /dev/null +++ b/e2e/parallel-requests/envoy.yaml @@ -0,0 +1,117 @@ +--- +static_resources: + listeners: + - name: main + address: + socket_address: + address: 0.0.0.0 + port_value: 80 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http + use_remote_address: true + xff_num_trusted_hops: 1 + route_config: + name: local_route + virtual_hosts: + - name: local_service + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: upstream + http_filters: + - name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + name: kuadrant_wasm + root_id: kuadrant_wasm + vm_config: + vm_id: vm.sentinel.kuadrant_wasm + runtime: envoy.wasm.runtime.v8 + code: + local: + filename: /opt/kuadrant/wasm/wasm_shim.wasm + allow_precompiled: true + configuration: + "@type": "type.googleapis.com/google.protobuf.StringValue" + value: > + { + "services": { + "limitador": { + "type": "ratelimit", + "endpoint": "limitador", + "failureMode": "deny" + } + }, + "actionSets": [ + { + "name": "example action set", + "routeRuleConditions": { + "hostnames": [ + "*.example.com" + ] + }, + "actions": [ + { + "service": "limitador", + "scope": "a", + "data": [ + { + "expression": { + "key": "limit_to_be_activated", + "value": "1" + } + } + ] + } + ] + } + ] + } + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: upstream + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: round_robin + load_assignment: + cluster_name: upstream + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: upstream + port_value: 3000 + - name: limitador + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: round_robin + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicit_http_config: + http2_protocol_options: {} + load_assignment: + cluster_name: limitador + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: limitador + port_value: 8081 +admin: + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 diff --git a/e2e/parallel-requests/limits.yaml b/e2e/parallel-requests/limits.yaml new file mode 100644 index 0000000..0c53707 --- /dev/null +++ b/e2e/parallel-requests/limits.yaml @@ -0,0 +1,7 @@ +--- +- namespace: ratelimit-source + max_value: 30 + seconds: 60 + conditions: + - "limit_to_be_activated == '1'" + variables: [] diff --git a/e2e/parallel-requests/run-parallel-requests.sh b/e2e/parallel-requests/run-parallel-requests.sh new file mode 100755 index 0000000..0f7cde6 --- /dev/null +++ b/e2e/parallel-requests/run-parallel-requests.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +if ! command -v curl &>/dev/null +then + echo "curl not found..." >&2 + exit 1 +fi + +curl --silent --output /dev/null --fail --max-time 5 --resolve test.example.com:18000:127.0.0.1 http://test.example.com:18000 & REQ1=$! +curl --silent --output /dev/null --fail --max-time 5 --resolve test.example.com:18000:127.0.0.1 http://test.example.com:18000 & REQ2=$! +curl --silent --output /dev/null --fail --max-time 5 --resolve test.example.com:18000:127.0.0.1 http://test.example.com:18000 & REQ3=$! + +wait $REQ1 +RET_REQ1=$? +echo "REQ1 returned $RET_REQ1" +if test "$RET_REQ1" != "0"; then + echo "REQ1 exited with abnormal status" + exit 1; +fi + +wait $REQ2 +RET_REQ2=$? +echo "REQ2 returned $RET_REQ2" +if test "$RET_REQ2" != "0"; then + echo "REQ2 exited with abnormal status" + exit 1; +fi + +wait $REQ3 +RET_REQ3=$? +echo "REQ3 returned $RET_REQ3" +if test "$RET_REQ3" != "0"; then + echo "REQ3 exited with abnormal status" + exit 1; +fi + +echo "All requests succeeded" +exit 0