From 7df17c5fa5b1105b6af172223b69e98b91570887 Mon Sep 17 00:00:00 2001
From: sabevzenko
Date: Mon, 20 May 2024 11:18:40 +0300
Subject: [PATCH 1/3] pandora scenario: local block docs
7eb87e73be643c6cd89eacda49777b507ce609d4
---
.../unreleased/Added-20240517-144818.yaml | 3 +
.../unreleased/Added-20240517-144851.yaml | 3 +
.mapping.json | 4 +
README.md | 9 +-
.../providers/scenario/config/config.go | 1 +
.../providers/scenario/grpc/provider.go | 2 +-
.../providers/scenario/http/provider.go | 2 +-
.../providers/scenario/test/decode_test.go | 9 +-
.../scenario/testdata/http_payload.yaml | 9 +-
docs/eng/scenario-grpc-generator.md | 27 ++++-
docs/eng/scenario-http-generator.md | 30 +++++-
docs/eng/scenario/functions.md | 22 ++++
docs/eng/scenario/locals.md | 100 ++++++++++++++++++
docs/rus/scenario-grpc-generator.md | 27 ++++-
docs/rus/scenario-http-generator.md | 30 +++++-
docs/rus/scenario/functions.md | 21 ++++
docs/rus/scenario/locals.md | 100 ++++++++++++++++++
17 files changed, 367 insertions(+), 32 deletions(-)
create mode 100644 .changes/unreleased/Added-20240517-144818.yaml
create mode 100644 .changes/unreleased/Added-20240517-144851.yaml
create mode 100644 docs/eng/scenario/locals.md
create mode 100644 docs/rus/scenario/locals.md
diff --git a/.changes/unreleased/Added-20240517-144818.yaml b/.changes/unreleased/Added-20240517-144818.yaml
new file mode 100644
index 000000000..f1b861409
--- /dev/null
+++ b/.changes/unreleased/Added-20240517-144818.yaml
@@ -0,0 +1,3 @@
+kind: Added
+body: scenario config local block in yaml
+time: 2024-05-17T14:48:18.485698+02:00
diff --git a/.changes/unreleased/Added-20240517-144851.yaml b/.changes/unreleased/Added-20240517-144851.yaml
new file mode 100644
index 000000000..a9b280e96
--- /dev/null
+++ b/.changes/unreleased/Added-20240517-144851.yaml
@@ -0,0 +1,3 @@
+kind: Added
+body: scenario config local block documentation
+time: 2024-05-17T14:48:51.970879+02:00
diff --git a/.mapping.json b/.mapping.json
index da0684284..e40dde03a 100644
--- a/.mapping.json
+++ b/.mapping.json
@@ -1,6 +1,8 @@
{
".changes/header.tpl.md":"load/projects/pandora/.changes/header.tpl.md",
".changes/unreleased/.gitkeep":"load/projects/pandora/.changes/unreleased/.gitkeep",
+ ".changes/unreleased/Added-20240517-144818.yaml":"load/projects/pandora/.changes/unreleased/Added-20240517-144818.yaml",
+ ".changes/unreleased/Added-20240517-144851.yaml":"load/projects/pandora/.changes/unreleased/Added-20240517-144851.yaml",
".changes/v0.5.04.md":"load/projects/pandora/.changes/v0.5.04.md",
".changes/v0.5.05.md":"load/projects/pandora/.changes/v0.5.05.md",
".changes/v0.5.06.md":"load/projects/pandora/.changes/v0.5.06.md",
@@ -273,6 +275,7 @@
"docs/eng/scenario-grpc-generator.md":"load/projects/pandora/docs/eng/scenario-grpc-generator.md",
"docs/eng/scenario-http-generator.md":"load/projects/pandora/docs/eng/scenario-http-generator.md",
"docs/eng/scenario/functions.md":"load/projects/pandora/docs/eng/scenario/functions.md",
+ "docs/eng/scenario/locals.md":"load/projects/pandora/docs/eng/scenario/locals.md",
"docs/eng/scenario/variable_source.md":"load/projects/pandora/docs/eng/scenario/variable_source.md",
"docs/eng/startup.md":"load/projects/pandora/docs/eng/startup.md",
"docs/eng/tutorial.md":"load/projects/pandora/docs/eng/tutorial.md",
@@ -304,6 +307,7 @@
"docs/rus/scenario-grpc-generator.md":"load/projects/pandora/docs/rus/scenario-grpc-generator.md",
"docs/rus/scenario-http-generator.md":"load/projects/pandora/docs/rus/scenario-http-generator.md",
"docs/rus/scenario/functions.md":"load/projects/pandora/docs/rus/scenario/functions.md",
+ "docs/rus/scenario/locals.md":"load/projects/pandora/docs/rus/scenario/locals.md",
"docs/rus/scenario/variable_source.md":"load/projects/pandora/docs/rus/scenario/variable_source.md",
"docs/rus/startup.md":"load/projects/pandora/docs/rus/startup.md",
"docs/rus/tutorial.md":"load/projects/pandora/docs/rus/tutorial.md",
diff --git a/README.md b/README.md
index 4a3cd77fc..5d26d2cfa 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,9 @@
Pandora is a high-performance load generator in Go language. It has built-in HTTP(S) and HTTP/2 support and you can write your own load scenarios in Go, compiling them just before your test.
+## Documentation
+[Documentation](https://yandex.github.io/pandora/)
+
## How to start
### Binary releases
@@ -71,9 +74,3 @@ Create changelog release file - `changie batch v0.5.21`
Same for next version - `changie batch $(changie next patch)`
Merge to main CHANGELOG.md file - `changie merge`
-
-## Documentation
-[Documentation](https://yandex.github.io/pandora/)
-
-## Old Documentation
-[ReadTheDocs](https://yandexpandora.readthedocs.io/)
diff --git a/components/providers/scenario/config/config.go b/components/providers/scenario/config/config.go
index a8bbe05ae..71e17cc2b 100644
--- a/components/providers/scenario/config/config.go
+++ b/components/providers/scenario/config/config.go
@@ -13,6 +13,7 @@ import (
// AmmoConfig is a config for dynamic converting from map[string]interface{}
type AmmoConfig struct {
+ Locals map[string]any
VariableSources []vs.VariableSource `config:"variable_sources"`
Requests []RequestConfig
Calls []CallConfig
diff --git a/components/providers/scenario/grpc/provider.go b/components/providers/scenario/grpc/provider.go
index bb0f1fa78..f8b26e7d4 100644
--- a/components/providers/scenario/grpc/provider.go
+++ b/components/providers/scenario/grpc/provider.go
@@ -15,7 +15,7 @@ var _ core.Provider = (*scenario.Provider[*gun.Scenario])(nil)
const defaultSinkSize = 100
func NewProvider(fs afero.Fs, conf scenario.ProviderConfig) (core.Provider, error) {
- const op = "config.NewProvider"
+ const op = "scenario_grpc.NewProvider"
ammoCfg, err := config.ReadAmmoConfig(fs, conf.File)
if err != nil {
return nil, fmt.Errorf("%s ReadAmmoConfig %w", op, err)
diff --git a/components/providers/scenario/http/provider.go b/components/providers/scenario/http/provider.go
index 607df371d..e3021e8ec 100644
--- a/components/providers/scenario/http/provider.go
+++ b/components/providers/scenario/http/provider.go
@@ -15,7 +15,7 @@ var _ core.Provider = (*scenario.Provider[*gun.Scenario])(nil)
const defaultSinkSize = 100
func NewProvider(fs afero.Fs, conf scenario.ProviderConfig) (core.Provider, error) {
- const op = "scenario.NewProvider"
+ const op = "scenario_http.NewProvider"
ammoCfg, err := config.ReadAmmoConfig(fs, conf.File)
if err != nil {
return nil, fmt.Errorf("%s ReadAmmoConfig %w", op, err)
diff --git a/components/providers/scenario/test/decode_test.go b/components/providers/scenario/test/decode_test.go
index 110a8fff9..14828366d 100644
--- a/components/providers/scenario/test/decode_test.go
+++ b/components/providers/scenario/test/decode_test.go
@@ -6,6 +6,7 @@ import (
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/yandex/pandora/components/providers/scenario/config"
_import "github.com/yandex/pandora/components/providers/scenario/import"
"github.com/yandex/pandora/core/plugin/pluginconfig"
@@ -22,12 +23,14 @@ func Test_ReadConfig_YamlAndHclSameResult(t *testing.T) {
t.Run("http", func(t *testing.T) {
fromHCL, err := config.ReadAmmoConfig(testFS, "../testdata/http_payload.hcl")
- assert.NoError(t, err)
+ require.NoError(t, err)
+ fromHCL.Locals = nil
fromYaml, err := config.ReadAmmoConfig(testFS, "../testdata/http_payload.yaml")
- assert.NoError(t, err)
+ require.NoError(t, err)
+ fromYaml.Locals = nil
- assert.Equal(t, fromHCL, fromYaml)
+ require.Equal(t, fromHCL, fromYaml)
})
}
diff --git a/components/providers/scenario/testdata/http_payload.yaml b/components/providers/scenario/testdata/http_payload.yaml
index 3141f1858..614be4ba5 100644
--- a/components/providers/scenario/testdata/http_payload.yaml
+++ b/components/providers/scenario/testdata/http_payload.yaml
@@ -1,3 +1,7 @@
+locals:
+ global-headers: &global-headers
+ Content-Type: application/json
+ Useragent: Yandex
variable_sources:
- name: users
type: file/csv
@@ -20,9 +24,8 @@ requests:
- name: auth_req
method: POST
uri: /auth
- headers: &global-headers
- Content-Type: application/json
- Useragent: Yandex
+ headers:
+ <<: *global-headers
tag: auth
body: |
{"user_id": {{.request.auth_req.preprocessor.user_id}}}
diff --git a/docs/eng/scenario-grpc-generator.md b/docs/eng/scenario-grpc-generator.md
index b946eb3b3..cdc2add3e 100644
--- a/docs/eng/scenario-grpc-generator.md
+++ b/docs/eng/scenario-grpc-generator.md
@@ -11,6 +11,7 @@
- [General principle](#general-principle)
- [HCL example](#hcl-example)
- [YAML example](#yaml-example)
+ - [Locals](#locals)
- [Features](#features)
- [Calls](#calls)
- [Templater](#templater)
@@ -87,6 +88,18 @@ The Call is a gRPC call. It has standard gRPC call fields plus additional ones.
### HCL example
```terraform
+locals {
+ common_meta = {
+ "metadata" = "server.proto"
+ }
+ next = "next"
+}
+locals {
+ auth_meta = merge(local.common_meta, {
+ authorization = "{{.request.auth_req.postprocessor.token}}"
+ })
+ next = "next"
+}
variable_source "users" "file/csv" {
file = "users.csv"
fields = ["user_id", "login", "pass"]
@@ -106,9 +119,7 @@ variable_source "variables" "variables" {
call "auth_req" {
call = "target.TargetService.Auth"
tag = "auth"
- metadata = {
- "metadata" = "server.proto"
- }
+ metadata = local.auth_meta
preprocessor "prepare" {
mapping = {
user = "source.users[next]"
@@ -121,7 +132,6 @@ EOF
payload = ["token"]
status_code = 200
}
-}}
}
scenario "scenario_name" {
@@ -139,6 +149,9 @@ You can also see an example in the tests https://github.com/yandex/pandora/blob/
### YAML example
```yaml
+locals:
+ my-meta: &global-meta
+ metadata: "server.proto"
variable_sources:
- type: "file/csv"
name: "users"
@@ -155,7 +168,7 @@ calls:
tag: auth
method: POST
metadata:
- metadata: "server.proto"
+ <<: *global-meta
preprocessors:
- type: prepare
mapping:
@@ -175,6 +188,10 @@ scenarios:
]
```
+### Locals
+
+Про блок locals смотрите в отдельной [статье Locals](scenario/locals.md)
+
## Features
### Calls
diff --git a/docs/eng/scenario-http-generator.md b/docs/eng/scenario-http-generator.md
index edeb95424..1b458282b 100644
--- a/docs/eng/scenario-http-generator.md
+++ b/docs/eng/scenario-http-generator.md
@@ -11,6 +11,7 @@
- [General principle](#general-principle)
- [HCL example](#hcl-example)
- [YAML example](#yaml-example)
+ - [Locals](#locals)
- [Features](#features)
- [Requests](#requests)
- [Templater](#templater)
@@ -97,6 +98,19 @@ Request - HTTP request. Has the standard HTTP request fields plus additional fie
### HCL example
```terraform
+locals {
+ common_headers = {
+ Content-Type = "application/json"
+ Useragent = "Yandex"
+ }
+ next = "next"
+}
+locals {
+ auth_headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
+ next = "next"
+}
variable_source "source_name" "file/csv" {
file = "file.csv"
fields = ["id", "name"]
@@ -107,9 +121,9 @@ variable_source "source_name" "file/csv" {
request "request_name" {
method = "POST"
uri = "/uri"
- headers = {
- HeaderName = "header value"
- }
+ headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
tag = "tag"
body = <
@@ -144,6 +158,10 @@ scenario "scenario_name" {
### YAML example
```yaml
+locals:
+ my-headers: &global-headers
+ Content-Type: application/json
+ Useragent: Yandex
variable_sources:
- type: "file/csv"
name: "source_name"
@@ -157,7 +175,7 @@ requests:
uri: '/uri'
method: POST
headers:
- Header-Name: "header value"
+ <<: *global-headers
tag: tag
body: ''
preprocessor:
@@ -179,6 +197,10 @@ scenarios:
]
```
+### Locals
+
+See [Locals article](scenario/locals.md)
+
## Features
### Requests
diff --git a/docs/eng/scenario/functions.md b/docs/eng/scenario/functions.md
index 3e0026b3e..357166ac2 100644
--- a/docs/eng/scenario/functions.md
+++ b/docs/eng/scenario/functions.md
@@ -135,6 +135,28 @@ preprocessor {
}
```
+# HCL functions
+
+You can use follow function
+
+- [coalesce](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/coalesce)
+- [coalescelist](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/coalescelist)
+- [compact](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/compact)
+- [concat](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/concat)
+- [distinct](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/distinct)
+- [element](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/element)
+- [flatten](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/flatten)
+- [index](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/index-fn)
+- [keys](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/keys)
+- [lookup](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/lookup)
+- [merge](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/merge)
+- [reverse](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/reverse)
+- [slice](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/slice)
+- [sort](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/sort)
+- [split](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/string/split)
+- [values](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/values)
+- [zipmap](https://developer.hashicorp.com/packer/docs/templates/hcl_templates/functions/collection/zipmap)
+
---
diff --git a/docs/eng/scenario/locals.md b/docs/eng/scenario/locals.md
new file mode 100644
index 000000000..bbc9f82a3
--- /dev/null
+++ b/docs/eng/scenario/locals.md
@@ -0,0 +1,100 @@
+[Home](../../index.md)
+
+---
+
+# Locals
+
+Foreword:
+
+Creating a script from HCL consists of two stages:
+- Parsing stage - converts the HCL file into the internal structure of the generator.
+- Execution stage - involves the steps of:
+ - Preprocessing
+ - Templating
+ - Postprocessing
+
+This article focuses on the parsing stage.
+
+## HCL
+
+Just like in Terraform, you can use the `locals` block, which allows you to create additional variables.
+It is important to note that these variables are only utilized during the parsing of HCL and cannot be used
+during the execution stage.
+
+### Functions
+
+You can use [HCL functions](functions.md#hcl-functions).
+
+### Example of Use
+
+You can use `locals` variables to define common headers.
+
+Note the use of the `merge()` function.
+
+```hcl
+locals {
+ common_headers = {
+ Content-Type = "application/json"
+ Useragent = "Yandex"
+ }
+ next = "next"
+}
+locals {
+ // Merge the new variable with the local variable local.common_headers
+ auth_headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
+ next = "next"
+}
+
+request "list_req" {
+ // Merge the new variable with the local variable local.common_headers
+ method = "GET"
+ headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
+ tag = "list"
+ uri = "/list"
+
+ postprocessor "var/jsonpath" {
+ mapping = {
+ item_id = "$.items[0]"
+ items = "$.items"
+ }
+ }
+}
+```
+
+## YAML
+
+In YAML format, you can use anchors.
+
+For common variables, you can use the `locals` helper block.
+
+```yaml
+locals:
+ global-headers: &global-headers
+ Content-Type: application/json
+ Useragent: Yandex
+
+requests:
+ - name: auth_req
+ headers:
+ <<: *global-headers
+ - name: list_req
+ headers: &auth-headers
+ <<: *global-headers
+ Authorization: Bearer {{.request.auth_req.postprocessor.token}}
+ - name: order_req
+ headers:
+ <<: *auth-headers
+```
+
+---
+
+- [Scenario generator / HTTP](../scenario-http-generator.md)
+- [Scenario generator / gRPC](../scenario-grpc-generator.md)
+
+---
+
+[Home](../../index.md)
diff --git a/docs/rus/scenario-grpc-generator.md b/docs/rus/scenario-grpc-generator.md
index e708725d5..3032476e4 100644
--- a/docs/rus/scenario-grpc-generator.md
+++ b/docs/rus/scenario-grpc-generator.md
@@ -11,6 +11,7 @@
- [Общий принцип](#общий-принцип)
- [HCL пример](#hcl-пример)
- [YAML пример](#yaml-пример)
+ - [Locals](#locals)
- [Возможности](#возможности)
- [Вызовы](#вызовы)
- [Шаблонизатор](#шаблонизатор)
@@ -87,6 +88,18 @@ ammo:
### HCL пример
```terraform
+locals {
+ common_meta = {
+ "metadata" = "server.proto"
+ }
+ next = "next"
+}
+locals {
+ auth_meta = merge(local.common_meta, {
+ authorization = "{{.request.auth_req.postprocessor.token}}"
+ })
+ next = "next"
+}
variable_source "users" "file/csv" {
file = "users.csv"
fields = ["user_id", "login", "pass"]
@@ -106,9 +119,7 @@ variable_source "variables" "variables" {
call "auth_req" {
call = "target.TargetService.Auth"
tag = "auth"
- metadata = {
- "metadata" = "server.proto"
- }
+ metadata = local.auth_meta
preprocessor "prepare" {
mapping = {
user = "source.users[next]"
@@ -121,7 +132,6 @@ EOF
payload = ["token"]
status_code = 200
}
-}}
}
scenario "scenario_name" {
@@ -139,6 +149,9 @@ scenario "scenario_name" {
### YAML пример
```yaml
+locals:
+ my-meta: &global-meta
+ metadata: "server.proto"
variable_sources:
- type: "file/csv"
name: "users"
@@ -155,7 +168,7 @@ calls:
tag: auth
method: POST
metadata:
- metadata: "server.proto"
+ <<: *global-meta
preprocessors:
- type: prepare
mapping:
@@ -175,6 +188,10 @@ scenarios:
]
```
+### Locals
+
+Про блок locals смотрите в отдельной [статье Locals](scenario/locals.md)
+
## Возможности
### Вызовы
diff --git a/docs/rus/scenario-http-generator.md b/docs/rus/scenario-http-generator.md
index d3e4bb156..bc1d325f0 100644
--- a/docs/rus/scenario-http-generator.md
+++ b/docs/rus/scenario-http-generator.md
@@ -11,6 +11,7 @@
- [Общий принцип](#общий-принцип)
- [HCL пример](#hcl-пример)
- [YAML пример](#yaml-пример)
+ - [Locals](#locals)
- [Возможности](#возможности)
- [Запросы](#запросы)
- [Шаблонизатор](#шаблонизатор)
@@ -97,6 +98,19 @@ ammo:
### HCL пример
```terraform
+locals {
+ common_headers = {
+ Content-Type = "application/json"
+ Useragent = "Yandex"
+ }
+ next = "next"
+}
+locals {
+ auth_headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
+ next = "next"
+}
variable_source "source_name" "file/csv" {
file = "file.csv"
fields = ["id", "name"]
@@ -107,9 +121,9 @@ variable_source "source_name" "file/csv" {
request "request_name" {
method = "POST"
uri = "/uri"
- headers = {
- HeaderName = "header value"
- }
+ headers = merge(local.common_headers, {
+ Authorization = "Bearer {{.request.auth_req.postprocessor.token}}"
+ })
tag = "tag"
body = <
@@ -147,6 +161,10 @@ scenario "scenario_name" {
### YAML пример
```yaml
+locals:
+ my-headers: &global-headers
+ Content-Type: application/json
+ Useragent: Yandex
variable_sources:
- type: "file/csv"
name: "source_name"
@@ -160,7 +178,7 @@ requests:
uri: '/uri'
method: POST
headers:
- Header-Name: "header value"
+ <<: *global-headers
tag: tag
body: '