From 86931b5fb777273bdb34a361a0ea2b64b215eb93 Mon Sep 17 00:00:00 2001 From: sabevzenko Date: Tue, 23 Apr 2024 16:55:43 +0300 Subject: [PATCH 1/8] scenario random functions: docs c31b364c1b102d10dc59f1e2092fac3637101de1 --- docs/eng/scenario/functions.md | 44 +++++++++++++++++++++++++++------- docs/rus/scenario/functions.md | 44 +++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/docs/eng/scenario/functions.md b/docs/eng/scenario/functions.md index 287f17503..3e0026b3e 100644 --- a/docs/eng/scenario/functions.md +++ b/docs/eng/scenario/functions.md @@ -47,27 +47,53 @@ functions can be found at [Go template functions](https://pkg.go.dev/text/templa ### uuid -`{{ uuid }}` +```gotemplate +{% raw %}{{ uuid }}{% endraw %} +``` ### randInt -`{{ randInt }}` +no arguments +```gotemplate +{% raw %}{{ randInt }}{% endraw %} +``` -`{{ randInt 10 }}` +1 argument +```gotemplate +{% raw %}{{ randInt 10 }}{% endraw %} +``` -`{{ randInt 100 200 }}` +2 arguments +```gotemplate +{% raw %}{{ randInt 100 200 }}{% endraw %} +``` -`{{ randInt 200 .source.global.max_rand_int }}` +2 arguments using source variable +```gotemplate +{% raw %}{{ randInt 200 .source.global.max_rand_int }}{% endraw %} +``` ### randString -`{{ randString }}` +no arguments +```gotemplate +{% raw %}{{ randString }}{% endraw %} +``` -`{{ randString 10 }}` +1 argument +```gotemplate +{% raw %}{{ randString 10 }}{% endraw %} +``` -`{{ randString 10 abcde }}` +2 arguments +```gotemplate +{% raw %}{{ randString 10 abcde }}{% endraw %} +``` -`{{ randString 20 .source.global.letters }}` +2 arguments using source variable +```gotemplate +{% raw %}{{ randString 20 .source.global.letters }}{% endraw %} +``` ## In the Data Source - variables diff --git a/docs/rus/scenario/functions.md b/docs/rus/scenario/functions.md index 8a28a3406..86fb38ef9 100644 --- a/docs/rus/scenario/functions.md +++ b/docs/rus/scenario/functions.md @@ -49,27 +49,53 @@ https://pkg.go.dev/text/template#hdr-Functions ### uuid -`{{ uuid }}` +```gotemplate +{% raw %}{{ uuid }}{% endraw %} +``` ### randInt -`{{ randInt }}` +без аргументов +```gotemplate +{% raw %}{{ randInt }}{% endraw %} +``` -`{{ randInt 10 }}` +1 аргумент +```gotemplate +{% raw %}{{ randInt 10 }}{% endraw %} +``` -`{{ randInt 100 200 }}` +2 аргумента +```gotemplate +{% raw %}{{ randInt 100 200 }}{% endraw %} +``` -`{{ randInt 200 .source.global.max_rand_int }}` +2 аргумента используем из источника переменных +```gotemplate +{% raw %}{{ randInt 200 .source.global.max_rand_int }}{% endraw %} +``` ### randString -`{{ randString }}` +без аргументов +```gotemplate +{% raw %}{{ randString }}{% endraw %} +``` -`{{ randString 10 }}` +1 аргумент +```gotemplate +{% raw %}{{ randString 10 }}{% endraw %} +``` -`{{ randString 10 abcde }}` +2 аргумента +```gotemplate +{% raw %}{{ randString 10 abcde }}{% endraw %} +``` -`{{ randString 20 .source.global.letters }}` +2 аргумента используем из источника переменных +```gotemplate +{% raw %}{{ randString 20 .source.global.letters }}{% endraw %} +``` ## В источник данных - variables From b397f9b4a4ef297528411d2309653aeb613d51ad Mon Sep 17 00:00:00 2001 From: sabevzenko Date: Tue, 23 Apr 2024 17:14:06 +0300 Subject: [PATCH 2/8] scenario random functions: docs faa522443f7de5b5b321cd18a4610fdc9a205aac --- docs/eng/scenario-grpc-generator.md | 13 +++++++++++++ docs/eng/scenario-http-generator.md | 1 + docs/rus/scenario-grpc-generator.md | 14 ++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/docs/eng/scenario-grpc-generator.md b/docs/eng/scenario-grpc-generator.md index b0b78ca4e..b946eb3b3 100644 --- a/docs/eng/scenario-grpc-generator.md +++ b/docs/eng/scenario-grpc-generator.md @@ -15,6 +15,7 @@ - [Calls](#calls) - [Templater](#templater) - [Variable names in templates](#variable-names-in-templates) + - [Functions in templates](#functions-in-templates) - [Preprocessors](#preprocessors) - [prepare](#prepare) - [Postprocessors](#postprocessors) @@ -208,6 +209,18 @@ Variable `item` from the `list_req` call preprocessor - `{% raw %}{{{.request.li Variable `token` from the `list_req` call is `{% raw %}{{{.request.list_req.postprocessor.token}}{% endraw %}` +##### Functions in Templates + +Since the standard Go templating engine is used, it is possible to use built-in functions available at https://pkg.go.dev/text/template#hdr-Functions. + +Additionally, some functions include: + +- randInt +- randString +- uuid + +For more details about randomization functions, see [more](scenario/functions.md). + #### Preprocessors Preprocessor - actions are performed before templating diff --git a/docs/eng/scenario-http-generator.md b/docs/eng/scenario-http-generator.md index c632dba3d..edeb95424 100644 --- a/docs/eng/scenario-http-generator.md +++ b/docs/eng/scenario-http-generator.md @@ -15,6 +15,7 @@ - [Requests](#requests) - [Templater](#templater) - [Variable names in templates](#variable-names-in-templates) + - [Functions in templates](#functions-in-templates) - [Preprocessors](#preprocessors) - [Postprocessors](#postprocessors) - [var/jsonpath](#varjsonpath) diff --git a/docs/rus/scenario-grpc-generator.md b/docs/rus/scenario-grpc-generator.md index 7cb7730c3..e708725d5 100644 --- a/docs/rus/scenario-grpc-generator.md +++ b/docs/rus/scenario-grpc-generator.md @@ -15,6 +15,7 @@ - [Вызовы](#вызовы) - [Шаблонизатор](#шаблонизатор) - [Имена переменных в шаблонрах](#имена-переменных-в-шаблонах) + - [Функции в шаблонах](#функции-в-шаблонах) - [Preprocessors](#preprocessors) - [prepare](#prepare) - [Postprocessors](#postprocessors) @@ -208,6 +209,19 @@ scenarios: Переменная `token` из вызова `list_req` - `{% raw %}{{.request.list_req.postprocessor.token}}{% endraw %}` +##### Функции в шаблонах + +Так как используется стандартные шаблонизатор Го в нем можно использовать встроенные функции +https://pkg.go.dev/text/template#hdr-Functions + +А так же некоторые функции + +- randInt +- randString +- uuid + +Подробнее про функции рандомизации см в [документации](scenario/functions.md) + #### Preprocessors Препроцессор - действия выполняются перед шаблонизацией From f54acd1f2bae1e19b43385adb7b0ba5d5fbb6efc Mon Sep 17 00:00:00 2001 From: nsamokhin Date: Wed, 24 Apr 2024 12:00:55 +0300 Subject: [PATCH 3/8] pandora scenario gun variables add support for "locals" block in hcl 0755b159bcce17c08dffde7f4441b9ec3b161244 --- components/providers/scenario/config/hcl.go | 115 +++++++++++++++++- .../scenario/testdata/http_payload.hcl | 33 ++--- .../scenario/testdata/http_payload.yaml | 11 +- 3 files changed, 132 insertions(+), 27 deletions(-) diff --git a/components/providers/scenario/config/hcl.go b/components/providers/scenario/config/hcl.go index 958bc0761..d406c6e23 100644 --- a/components/providers/scenario/config/hcl.go +++ b/components/providers/scenario/config/hcl.go @@ -4,8 +4,13 @@ import ( "fmt" "io" - "github.com/hashicorp/hcl/v2/hclsimple" + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/gohcl" + "github.com/hashicorp/hcl/v2/hclparse" "github.com/spf13/afero" + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" + "github.com/zclconf/go-cty/cty/function/stdlib" ) type AmmoHCL struct { @@ -91,14 +96,114 @@ type CallPreprocessorHCL struct { func ParseHCLFile(file afero.File) (AmmoHCL, error) { const op = "hcl.ParseHCLFile" - var config AmmoHCL bytes, err := io.ReadAll(file) if err != nil { return AmmoHCL{}, fmt.Errorf("%s, io.ReadAll, %w", op, err) } - err = hclsimple.Decode(file.Name(), bytes, nil, &config) - if err != nil { - return AmmoHCL{}, fmt.Errorf("%s, hclsimple.Decode, %w", op, err) + + parser := hclparse.NewParser() + f, diag := parser.ParseHCL(bytes, file.Name()) + if diag.HasErrors() { + return AmmoHCL{}, diag + } + + localsBodyContent, remainingBody, diag := f.Body.PartialContent(localsSchema()) + // diag still may have errors, because PartialContent doesn't know about Functions and self-references to locals + if localsBodyContent == nil || remainingBody == nil { + return AmmoHCL{}, diag + } + + hclContext, diag := decodeLocals(localsBodyContent) + if diag.HasErrors() { + return AmmoHCL{}, diag + } + + var config AmmoHCL + diag = gohcl.DecodeBody(remainingBody, hclContext, &config) + if diag.HasErrors() { + return AmmoHCL{}, diag } return config, nil } + +func decodeLocals(localsBodyContent *hcl.BodyContent) (*hcl.EvalContext, hcl.Diagnostics) { + vars := map[string]cty.Value{} + hclContext := buildHclContext(vars) + for _, block := range localsBodyContent.Blocks { + if block == nil { + continue + } + if block.Type == "locals" { + newVars, err := decodeLocalBlock(block, hclContext) + if err != nil { + return nil, err + } + hclContext = buildHclContext(mergeMaps(vars, newVars)) + } + } + return hclContext, nil +} + +func mergeMaps[K comparable, V any](to, from map[K]V) map[K]V { + for k, v := range from { + to[k] = v + } + return to +} + +func decodeLocalBlock(localsBlock *hcl.Block, hclContext *hcl.EvalContext) (map[string]cty.Value, hcl.Diagnostics) { + attrs, err := localsBlock.Body.JustAttributes() + if err != nil { + return nil, err + } + + vars := map[string]cty.Value{} + for name, attr := range attrs { + val, err := attr.Expr.Value(hclContext) + if err != nil { + return nil, err + } + vars[name] = val + } + + return vars, nil +} + +func localsSchema() *hcl.BodySchema { + return &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + { + Type: "locals", + LabelNames: []string{}, + }, + }, + } +} + +func buildHclContext(vars map[string]cty.Value) *hcl.EvalContext { + return &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "local": cty.ObjectVal(vars), + }, + Functions: map[string]function.Function{ + // collection functions + "coalesce": stdlib.CoalesceFunc, + "coalescelist": stdlib.CoalesceListFunc, + "compact": stdlib.CompactFunc, + "concat": stdlib.ConcatFunc, + "distinct": stdlib.DistinctFunc, + "element": stdlib.ElementFunc, + "flatten": stdlib.FlattenFunc, + "index": stdlib.IndexFunc, + "keys": stdlib.KeysFunc, + "lookup": stdlib.LookupFunc, + "merge": stdlib.MergeFunc, + "reverse": stdlib.ReverseListFunc, + "slice": stdlib.SliceFunc, + "sort": stdlib.SortFunc, + "split": stdlib.SplitFunc, + "values": stdlib.ValuesFunc, + "zipmap": stdlib.ZipmapFunc, + }, + } +} diff --git a/components/providers/scenario/testdata/http_payload.hcl b/components/providers/scenario/testdata/http_payload.hcl index 7d3f897a1..d71e8d57d 100644 --- a/components/providers/scenario/testdata/http_payload.hcl +++ b/components/providers/scenario/testdata/http_payload.hcl @@ -1,4 +1,16 @@ - +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 "users" "file/csv" { file = "testdata/users.csv" fields = ["user_id", "name", "pass"] @@ -17,10 +29,7 @@ variable_source "variables" "variables" { request "auth_req" { method = "POST" uri = "/auth" - headers = { - Content-Type = "application/json" - Useragent = "Yandex" - } + headers = local.common_headers tag = "auth" body = < Date: Thu, 25 Apr 2024 14:39:51 +0300 Subject: [PATCH 4/8] -discard-overflow 80c0ba00e24577526f170cdf209b1696792a1597 --- .mapping.json | 2 + cli/cli.go | 9 ++++ docs/eng/best-practices.md | 1 + docs/eng/best_practices/discard-overflow.md | 48 +++++++++++++++++++++ docs/eng/config.md | 1 + docs/index.md | 5 ++- docs/rus/best-practices.md | 1 + docs/rus/best_practices/discard-overflow.md | 47 ++++++++++++++++++++ docs/rus/config.md | 1 + docs/rus/index.md | 5 ++- tests/acceptance/testdata/http/http.yaml | 2 +- tests/acceptance/testdata/http/http2.yaml | 2 +- 12 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 docs/eng/best_practices/discard-overflow.md create mode 100644 docs/rus/best_practices/discard-overflow.md diff --git a/.mapping.json b/.mapping.json index 418946b0e..2662c041c 100644 --- a/.mapping.json +++ b/.mapping.json @@ -257,6 +257,7 @@ "debian/source/format":"load/projects/pandora/debian/source/format", "docs/eng/architecture.md":"load/projects/pandora/docs/eng/architecture.md", "docs/eng/best-practices.md":"load/projects/pandora/docs/eng/best-practices.md", + "docs/eng/best_practices/discard-overflow.md":"load/projects/pandora/docs/eng/best_practices/discard-overflow.md", "docs/eng/best_practices/rps-per-instance.md":"load/projects/pandora/docs/eng/best_practices/rps-per-instance.md", "docs/eng/best_practices/shared-client.md":"load/projects/pandora/docs/eng/best_practices/shared-client.md", "docs/eng/config.md":"load/projects/pandora/docs/eng/config.md", @@ -286,6 +287,7 @@ "docs/rus/architecture.md":"load/projects/pandora/docs/rus/architecture.md", "docs/rus/best-practices.md":"load/projects/pandora/docs/rus/best-practices.md", "docs/rus/best_practices.md":"load/projects/pandora/docs/rus/best_practices.md", + "docs/rus/best_practices/discard-overflow.md":"load/projects/pandora/docs/rus/best_practices/discard-overflow.md", "docs/rus/best_practices/rps-per-instance.md":"load/projects/pandora/docs/rus/best_practices/rps-per-instance.md", "docs/rus/best_practices/shared-client.md":"load/projects/pandora/docs/rus/best_practices/shared-client.md", "docs/rus/config.md":"load/projects/pandora/docs/rus/config.md", diff --git a/cli/cli.go b/cli/cli.go index 40dee0285..a5c0cd01f 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -235,6 +235,15 @@ func readConfig(args []string) *CliConfig { log.Fatal("Config read failed", zap.Error(err)) } } + pools := v.Get("pools").([]any) + for i, pool := range pools { + poolMap := pool.(map[string]any) + if _, ok := poolMap["discard_overflow"]; !ok { + poolMap["discard_overflow"] = true + } + pools[i] = poolMap + } + v.Set("pools", pools) conf := DefaultConfig() err = config.DecodeAndValidate(v.AllSettings(), conf) diff --git a/docs/eng/best-practices.md b/docs/eng/best-practices.md index ae2721152..9063978ec 100644 --- a/docs/eng/best-practices.md +++ b/docs/eng/best-practices.md @@ -1,4 +1,5 @@ # Практики использования +- [Discard Overflow](best_practices/discard-overflow.md) - [RPS per instance](./best_practices/rps-per-instance.md) - [Shared client](best_practices/shared-client.md) \ No newline at end of file diff --git a/docs/eng/best_practices/discard-overflow.md b/docs/eng/best_practices/discard-overflow.md new file mode 100644 index 000000000..d57a1d2c0 --- /dev/null +++ b/docs/eng/best_practices/discard-overflow.md @@ -0,0 +1,48 @@ +[Home](../../index.md) + +--- + +# Discard Overflow + +When you specify a [load profile](../load-profile.md), the generator calculates the order and timing of requests. This +can be referred to as the schedule of requests execution. Pandora's scheduler is responsible for this. It receives +requests from the provider and according to this schedule, passes them to the instances. Each instance then executes the +requests sequentially. + +There may be situations where the scheduler believes it's time to execute the next request, but all instances are busy +waiting for their current requests to complete. In this case, the scheduler can proceed in one of two ways: + +1. Wait until an instance becomes available and then pass the request to it later than scheduled. +2. Discard this request and wait for the next one, anticipating that by the time the next request is due, one of the + instances will have become available. + +The instance setting `discard_overflow` determines which behavior to follow. + +1. `discard_overflow: false` - Flexible schedule adherence. The generator ensures that all planned requests are sent. + The test duration depends on the performance of the service being tested, average response time, and the number of + instances. +2. `discard_overflow: true` - Strict adherence to the request schedule by the generator. Requests that do not fit into + the schedule are discarded. The test duration is predetermined. Requests that fail to meet the schedule are marked as + failed (with a net error `777`, and also tagged as discarded). + +By default, starting from version pandora@0.5.24, the setting `discard_overflow: true` is enabled. + +## A Bit of Theory + +When might the situation arise that forces the scheduler to choose the `discard_overflow` behavior? As mentioned +earlier, this occurs when it's time to execute a request, but there are no free instances available to process it. Why +can this happen? This typically occurs when the server's response time is high and the combination of the number of +instances and the load profile is not optimally selected. This is when `V > N * 1/rps`, where: + +- `V` is the response time of the server being tested (in seconds). +- `N` is the number of instances. + +To avoid such situations, you can: + +- Increase the number of instances. +- Decrease the load profile. +- Optimize the server being tested to reduce response time. + +--- + +[Home](../../index.md) diff --git a/docs/eng/config.md b/docs/eng/config.md index 23007c302..ef5c5a69e 100644 --- a/docs/eng/config.md +++ b/docs/eng/config.md @@ -27,6 +27,7 @@ pools: destination: ./phout.log # report file name rps-per-instance: false # rps section is counted for each instance or for the whole test. false - for the whole test + discard_overflow: true # strict adherence to the request schedule rps: # shooting schedule type: line # linear growth diff --git a/docs/index.md b/docs/index.md index 4c08062f3..4a3a104a8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,11 +12,14 @@ write your own load scenarios in Go, compiling them just before your test. - [Instance startup profile](eng/startup.md) - [HTTP providers](eng/providers.md) - [HTTP generators](eng/http-generator.md) -- [Scenario generator / HTTP](eng/scenario-http-generator.md) - [gRPC generators](eng/grpc-generator.md) +- [Scenario generator / HTTP](eng/scenario-http-generator.md) - [Scenario generator / gRPC](eng/scenario-grpc-generator.md) - [Custom guns](eng/custom.md) - [Best practices](eng/best-practices.md) + - [Discard Overflow](eng/best_practices/discard-overflow.md) + - [RPS на инстанс](eng/best_practices/rps-per-instance.md) + - [Общий транспорт](eng/best_practices/shared-client.md) - [Pandora’s performance](eng/performance.md) - [Architectural overview](eng/architecture.md) diff --git a/docs/rus/best-practices.md b/docs/rus/best-practices.md index d4294e564..192d8422c 100644 --- a/docs/rus/best-practices.md +++ b/docs/rus/best-practices.md @@ -1,4 +1,5 @@ # Практики использования +- [Discard Overflow](best_practices/discard-overflow.md) - [RPS на инстанс](best_practices/rps-per-instance.md) - [Общий транспорт](best_practices/shared-client.md) \ No newline at end of file diff --git a/docs/rus/best_practices/discard-overflow.md b/docs/rus/best_practices/discard-overflow.md new file mode 100644 index 000000000..d95b856f1 --- /dev/null +++ b/docs/rus/best_practices/discard-overflow.md @@ -0,0 +1,47 @@ +[Домой](../index.md) + +--- + +# Discard overflow + +Когда вы указываете [профиль нагрузки](../load-profile.md) генератор рассчитывает порядок и время выполнения запросов. +Можно назвать это расписанием выполнения запросов. За это отвечает планировщик Пандоры. Он получает запросы от +провайдера и по этому рассписанию передает инстансам. А каждый инстанс выполняет запросы последовательно. + +Может возникнуть ситуация, когда планировщик считает, что наступило время выполнить следующий запрос, но все инстансы +заняты ожиданием выполнения своего текущего запроса. В этом случае планировщик может поступать одним из 2-х способов. + +1. Дождаться, когда освободится какой-либо инстанс и передать запрос ему позже расписания +2. Отбросить этот запрос и ожидать следующий, рассчитывая на то, что когда наступит время следующего запроса, уже + освободится один из инстансов. + +За то, какому поведению следовать, отвечает настройка инстанса `discard_overflow` + +1. `discard_overflow: false` - нестрогое следование расписанию. Генератор гарантирует, что все запланированные запросы + будут отправлены. Время выполнения теста зависит от производительности тестируемого сервиса, среднего времени ответа + и количества инстансов. +2. `discard_overflow: true` - строгое следование генератором расписания запросов. Запросы, не уложившиеся + в расписание, отбрасываются. Время выполнения теста предопределено. Запросы, которые не укладываются в расписание, + помечаются неудавшимися (ошибка net `777`, а так же добавляется tag:discarded). + +По-умолчанию, начиная с версии pandora@0.5.24 настройка `discard_overflow: true` + +## Немного теории + +Когда может возникнуть ситуация, в которой планировщику придется выбрать поведение discard_overflow? Как было сказано +выше, когда наступает время выполнения запроса, но нет свободных инстансов, которые этот запрос могут выполнить. +Почему это может происходить? Когда время ответа от сервера высоко и комбинация кол-во инстансов и профиль нагрузки +выбраны не оптимально. То есть когда `V > N * 1/rps`, где + +- `V` - время ответа нагружаемого сервера (в секундах) +- `N` - кол-во инстансов + +Таким образом, чтобы избежать такой ситуации можно + +- увеличить кол-во инстансов +- уменьшить профиль нагрузки +- оптимизировать нагружаемый сервис, для уменьшения времени ответа + +--- + +[Домой](../index.md) diff --git a/docs/rus/config.md b/docs/rus/config.md index 6fdb54c8f..7b9ad9c3f 100644 --- a/docs/rus/config.md +++ b/docs/rus/config.md @@ -27,6 +27,7 @@ pools: destination: ./phout.log # report file name rps-per-instance: false # секция rps считается для каждого инстанса или для всего теста. false - для всего теста + discard_overflow: true # строгое следование генератором расписания запросов rps: # планировщик нагрузки type: line # тип планировщика diff --git a/docs/rus/index.md b/docs/rus/index.md index d47e81d92..e81c931df 100644 --- a/docs/rus/index.md +++ b/docs/rus/index.md @@ -11,11 +11,14 @@ Pandora - это высокопроизводительный генератор - [Профиль создание инстансов](startup.md) - [HTTP providers](providers.md) - [HTTP генератор](http-generator.md) -- [Сценарный генератор / HTTP](scenario-http-generator.md) - [gRPC генератор](grpc-generator.md) +- [Сценарный генератор / HTTP](scenario-http-generator.md) - [Сценарный генератор / gRPC](scenario-grpc-generator.md) - [Custom](custom.md) - [Практики использования](best-practices.md) + - [Discard Overflow](best_practices/discard-overflow.md) + - [RPS на инстанс](best_practices/rps-per-instance.md) + - [Общий транспорт](best_practices/shared-client.md) - [Производительность Pandora](performance.md) - [Архитектура](architecture.md) diff --git a/tests/acceptance/testdata/http/http.yaml b/tests/acceptance/testdata/http/http.yaml index cf19068bc..a5b10f75a 100644 --- a/tests/acceptance/testdata/http/http.yaml +++ b/tests/acceptance/testdata/http/http.yaml @@ -1,5 +1,5 @@ pools: - - id: "" + - id: "http pool" ammo: file: testdata/http/payload.uri type: uri diff --git a/tests/acceptance/testdata/http/http2.yaml b/tests/acceptance/testdata/http/http2.yaml index 57fa0f00d..9d4bcfae0 100644 --- a/tests/acceptance/testdata/http/http2.yaml +++ b/tests/acceptance/testdata/http/http2.yaml @@ -1,5 +1,5 @@ pools: - - id: "" + - id: "http2 pool" ammo: file: testdata/http/payload.uri type: uri From 57b3522de1c43f568fb316241f773a4c6cb963fb Mon Sep 17 00:00:00 2001 From: sabevzenko Date: Sat, 27 Apr 2024 12:47:03 +0300 Subject: [PATCH 5/8] answlog fix answlog fix 5e87661de95d4947595f0a6bf8c056cab5133e85 --- components/guns/http/base.go | 46 ++++--------- components/guns/http/base_test.go | 5 +- components/guns/http/client.go | 37 ----------- components/guns/http/connect.go | 37 ++++++----- components/guns/http/http.go | 80 ++++++++++++++--------- components/guns/http/http_test.go | 21 ++++-- components/guns/http_scenario/gun.go | 19 ++++++ components/guns/http_scenario/gun_test.go | 2 +- components/guns/http_scenario/import.go | 14 ++-- components/guns/http_scenario/new.go | 20 ++---- components/phttp/import/import.go | 19 +++--- lib/str/format_test.go | 1 - tests/http_scenario/main_test.go | 9 +-- 13 files changed, 151 insertions(+), 159 deletions(-) diff --git a/components/guns/http/base.go b/components/guns/http/base.go index 62f4651b4..51b5c37ad 100644 --- a/components/guns/http/base.go +++ b/components/guns/http/base.go @@ -25,16 +25,6 @@ const ( EmptyTag = "__EMPTY__" ) -type BaseGunConfig struct { - AutoTag AutoTagConfig `config:"auto-tag"` - AnswLog AnswLogConfig `config:"answlog"` - HTTPTrace HTTPTraceConfig `config:"httptrace"` - SharedClient struct { - ClientNumber int `config:"client-number,omitempty"` - Enabled bool `config:"enabled"` - } `config:"shared-client,omitempty"` -} - // AutoTagConfig configure automatic tags generation based on ammo URI. First AutoTag URI path elements becomes tag. // Example: /my/very/deep/page?id=23¶m=33 -> /my/very when uri-elements: 2. type AutoTagConfig struct { @@ -54,29 +44,10 @@ type HTTPTraceConfig struct { TraceEnabled bool `config:"trace"` } -func DefaultBaseGunConfig() BaseGunConfig { - return BaseGunConfig{ - AutoTag: AutoTagConfig{ - Enabled: false, - URIElements: 2, - NoTagOnly: true, - }, - AnswLog: AnswLogConfig{ - Enabled: false, - Path: "answ.log", - Filter: "error", - }, - HTTPTrace: HTTPTraceConfig{ - DumpEnabled: false, - TraceEnabled: false, - }, - } -} - -func NewBaseGun(clientConstructor ClientConstructor, cfg HTTPGunConfig, answLog *zap.Logger) *BaseGun { +func NewBaseGun(clientConstructor ClientConstructor, cfg GunConfig, answLog *zap.Logger) *BaseGun { client := clientConstructor(cfg.Client, cfg.Target) return &BaseGun{ - Config: cfg.Base, + Config: cfg, OnClose: func() error { client.CloseIdleConnections() return nil @@ -91,7 +62,7 @@ func NewBaseGun(clientConstructor ClientConstructor, cfg HTTPGunConfig, answLog type BaseGun struct { DebugLog bool // Automaticaly set in Bind if Log accepts debug messages. - Config BaseGunConfig + Config GunConfig Connect func(ctx context.Context) error // Optional hook. OnClose func() error // Optional. Called on Close(). Aggregator netsample.Aggregator // Lazy set via BindResultTo. @@ -183,6 +154,17 @@ func (b *BaseGun) Shoot(ammo Ammo) { b.Log.Warn("Invalid ammo", zap.Uint64("request", ammo.ID())) return } + + if b.Config.SSL { + req.URL.Scheme = "https" + } else { + req.URL.Scheme = "http" + } + if req.Host == "" { + req.Host = getHostWithoutPort(b.Config.Target) + } + req.URL.Host = b.Config.TargetResolved + if b.DebugLog { b.Log.Debug("Prepared ammo to shoot", zap.Stringer("url", req.URL)) } diff --git a/components/guns/http/base_test.go b/components/guns/http/base_test.go index 5608f78e3..1ece3fca9 100644 --- a/components/guns/http/base_test.go +++ b/components/guns/http/base_test.go @@ -63,7 +63,7 @@ func (s *BaseGunSuite) SetupSuite() { } func (s *BaseGunSuite) SetupTest() { - s.base = BaseGun{Config: DefaultBaseGunConfig()} + s.base = BaseGun{Config: DefaultHTTPGunConfig()} } func (s *BaseGunSuite) Test_BindResultTo_Panics() { @@ -335,8 +335,9 @@ func Test_Autotag(t *testing.T) { } func Test_ConfigDecode(t *testing.T) { - var conf BaseGunConfig + var conf GunConfig coretest.DecodeAndValidateT(t, ` +target: localhost:80 auto-tag: enabled: true uri-elements: 3 diff --git a/components/guns/http/client.go b/components/guns/http/client.go index 64f5fab0b..bdac18aea 100644 --- a/components/guns/http/client.go +++ b/components/guns/http/client.go @@ -173,43 +173,6 @@ func (c *panicOnHTTP1Client) Do(req *http.Request) (*http.Response, error) { return res, nil } -func WrapClientHostResolving(client Client, cfg HTTPGunConfig, targetResolved string) Client { - hostname := getHostWithoutPort(cfg.Target) - scheme := "http" - if cfg.SSL { - scheme = "https" - } - return &httpDecoratedClient{ - client: client, - scheme: scheme, - hostname: hostname, - targetResolved: targetResolved, - } -} - -type httpDecoratedClient struct { - client Client - scheme string - hostname string - targetResolved string -} - -func (c *httpDecoratedClient) Do(req *http.Request) (*http.Response, error) { - if req.Host == "" { - req.Host = c.hostname - } - - if c.targetResolved != "" { - req.URL.Host = c.targetResolved - } - req.URL.Scheme = c.scheme - return c.client.Do(req) -} - -func (c *httpDecoratedClient) CloseIdleConnections() { - c.client.CloseIdleConnections() -} - func checkHTTP2(state *tls.ConnectionState) error { if state == nil { return errors.New("http2: non TLS connection") diff --git a/components/guns/http/connect.go b/components/guns/http/connect.go index e102646f7..fe96f15a7 100644 --- a/components/guns/http/connect.go +++ b/components/guns/http/connect.go @@ -14,29 +14,32 @@ import ( "go.uber.org/zap" ) -func NewConnectGun(cfg HTTPGunConfig, answLog *zap.Logger) *BaseGun { - var wrappedConstructor = func(clientConfig ClientConfig, target string) Client { - scheme := "http" - if cfg.SSL { - scheme = "https" - } - client := newConnectClient(cfg.Client, cfg.Target) - return &httpDecoratedClient{ - client: client, - hostname: "", - targetResolved: cfg.Target, - scheme: scheme, - } +func NewConnectGun(cfg GunConfig, answLog *zap.Logger) *BaseGun { + if cfg.TargetResolved == "" { + cfg.TargetResolved = cfg.Target } - return NewBaseGun(wrappedConstructor, cfg, answLog) + return NewBaseGun(newConnectClient, cfg, answLog) } -func DefaultConnectGunConfig() HTTPGunConfig { - return HTTPGunConfig{ +func DefaultConnectGunConfig() GunConfig { + return GunConfig{ SSL: false, Client: DefaultClientConfig(), - Base: DefaultBaseGunConfig(), + AutoTag: AutoTagConfig{ + Enabled: false, + URIElements: 2, + NoTagOnly: true, + }, + AnswLog: AnswLogConfig{ + Enabled: false, + Path: "answ.log", + Filter: "error", + }, + HTTPTrace: HTTPTraceConfig{ + DumpEnabled: false, + TraceEnabled: false, + }, } } diff --git a/components/guns/http/http.go b/components/guns/http/http.go index 7fcc890e5..634a97bde 100644 --- a/components/guns/http/http.go +++ b/components/guns/http/http.go @@ -5,22 +5,23 @@ import ( "go.uber.org/zap" ) -type HTTPGunConfig struct { - Base BaseGunConfig `config:",squash"` - Client ClientConfig `config:",squash"` - Target string `validate:"endpoint,required"` - SSL bool +type GunConfig struct { + Client ClientConfig `config:",squash"` + Target string `validate:"endpoint,required"` + TargetResolved string `config:"-"` + SSL bool + + AutoTag AutoTagConfig `config:"auto-tag"` + AnswLog AnswLogConfig `config:"answlog"` + HTTPTrace HTTPTraceConfig `config:"httptrace"` + SharedClient struct { + ClientNumber int `config:"client-number,omitempty"` + Enabled bool `config:"enabled"` + } `config:"shared-client,omitempty"` } -func NewHTTP1Gun(cfg HTTPGunConfig, answLog *zap.Logger, targetResolved string) *BaseGun { - var wrappedConstructor = func(clientConfig ClientConfig, target string) Client { - return WrapClientHostResolving( - HTTP1ClientConstructor(cfg.Client, cfg.Target), - cfg, - targetResolved, - ) - } - return NewBaseGun(wrappedConstructor, cfg, answLog) +func NewHTTP1Gun(cfg GunConfig, answLog *zap.Logger) *BaseGun { + return NewBaseGun(HTTP1ClientConstructor, cfg, answLog) } func HTTP1ClientConstructor(clientConfig ClientConfig, target string) Client { @@ -32,19 +33,12 @@ func HTTP1ClientConstructor(clientConfig ClientConfig, target string) Client { var _ ClientConstructor = HTTP1ClientConstructor // NewHTTP2Gun return simple HTTP/2 gun that can shoot sequentially through one connection. -func NewHTTP2Gun(cfg HTTPGunConfig, answLog *zap.Logger, targetResolved string) (*BaseGun, error) { +func NewHTTP2Gun(cfg GunConfig, answLog *zap.Logger) (*BaseGun, error) { if !cfg.SSL { // Open issue on github if you really need this feature. return nil, errors.New("HTTP/2.0 over TCP is not supported. Please leave SSL option true by default.") } - var wrappedConstructor = func(clientConfig ClientConfig, target string) Client { - return WrapClientHostResolving( - HTTP2ClientConstructor(cfg.Client, cfg.Target), - cfg, - targetResolved, - ) - } - return NewBaseGun(wrappedConstructor, cfg, answLog), nil + return NewBaseGun(HTTP2ClientConstructor, cfg, answLog), nil } func HTTP2ClientConstructor(clientConfig ClientConfig, target string) Client { @@ -56,18 +50,44 @@ func HTTP2ClientConstructor(clientConfig ClientConfig, target string) Client { var _ ClientConstructor = HTTP2ClientConstructor -func DefaultHTTPGunConfig() HTTPGunConfig { - return HTTPGunConfig{ +func DefaultHTTPGunConfig() GunConfig { + return GunConfig{ SSL: false, - Base: DefaultBaseGunConfig(), Client: DefaultClientConfig(), + AutoTag: AutoTagConfig{ + Enabled: false, + URIElements: 2, + NoTagOnly: true, + }, + AnswLog: AnswLogConfig{ + Enabled: false, + Path: "answ.log", + Filter: "error", + }, + HTTPTrace: HTTPTraceConfig{ + DumpEnabled: false, + TraceEnabled: false, + }, } } -func DefaultHTTP2GunConfig() HTTPGunConfig { - return HTTPGunConfig{ +func DefaultHTTP2GunConfig() GunConfig { + return GunConfig{ Client: DefaultClientConfig(), - Base: DefaultBaseGunConfig(), - SSL: true, + AutoTag: AutoTagConfig{ + Enabled: false, + URIElements: 2, + NoTagOnly: true, + }, + AnswLog: AnswLogConfig{ + Enabled: false, + Path: "answ.log", + Filter: "error", + }, + HTTPTrace: HTTPTraceConfig{ + DumpEnabled: false, + TraceEnabled: false, + }, + SSL: true, } } diff --git a/components/guns/http/http_test.go b/components/guns/http/http_test.go index 907801252..d232b0aa5 100644 --- a/components/guns/http/http_test.go +++ b/components/guns/http/http_test.go @@ -42,7 +42,8 @@ func TestBaseGun_integration(t *testing.T) { conf.Target = host + ":80" targetResolved := strings.TrimPrefix(server.URL, "http://") results := &netsample.TestAggregator{} - httpGun := NewHTTP1Gun(conf, log, targetResolved) + conf.TargetResolved = targetResolved + httpGun := NewHTTP1Gun(conf, log) _ = httpGun.Bind(results, testDeps()) am := newAmmoReq(t, expectedReq) @@ -90,7 +91,8 @@ func TestHTTP(t *testing.T) { conf := DefaultHTTPGunConfig() conf.Target = server.Listener.Addr().String() conf.SSL = tt.https - gun := NewHTTP1Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + gun := NewHTTP1Gun(conf, log) var aggr netsample.TestAggregator _ = gun.Bind(&aggr, testDeps()) gun.Shoot(newAmmoURL(t, "/")) @@ -131,7 +133,8 @@ func TestHTTP_Redirect(t *testing.T) { conf := DefaultHTTPGunConfig() conf.Target = server.Listener.Addr().String() conf.Client.Redirect = tt.redirect - gun := NewHTTP1Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + gun := NewHTTP1Gun(conf, log) var aggr netsample.TestAggregator _ = gun.Bind(&aggr, testDeps()) gun.Shoot(newAmmoURL(t, "/redirect")) @@ -169,7 +172,8 @@ func TestHTTP_notSupportHTTP2(t *testing.T) { conf := DefaultHTTPGunConfig() conf.Target = server.Listener.Addr().String() conf.SSL = true - gun := NewHTTP1Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + gun := NewHTTP1Gun(conf, log) var results netsample.TestAggregator _ = gun.Bind(&results, testDeps()) gun.Shoot(newAmmoURL(t, "/")) @@ -191,7 +195,8 @@ func TestHTTP2(t *testing.T) { log := zap.NewNop() conf := DefaultHTTP2GunConfig() conf.Target = server.Listener.Addr().String() - gun, _ := NewHTTP2Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + gun, _ := NewHTTP2Gun(conf, log) var results netsample.TestAggregator _ = gun.Bind(&results, testDeps()) gun.Shoot(newAmmoURL(t, "/")) @@ -206,7 +211,8 @@ func TestHTTP2(t *testing.T) { log := zap.NewNop() conf := DefaultHTTP2GunConfig() conf.Target = server.Listener.Addr().String() - gun, _ := NewHTTP2Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + gun, _ := NewHTTP2Gun(conf, log) var results netsample.TestAggregator _ = gun.Bind(&results, testDeps()) var r interface{} @@ -229,7 +235,8 @@ func TestHTTP2(t *testing.T) { conf := DefaultHTTP2GunConfig() conf.Target = server.Listener.Addr().String() conf.SSL = false - _, err := NewHTTP2Gun(conf, log, conf.Target) + conf.TargetResolved = conf.Target + _, err := NewHTTP2Gun(conf, log) require.Error(t, err) }) } diff --git a/components/guns/http_scenario/gun.go b/components/guns/http_scenario/gun.go index cbf7a021b..9b173a65b 100644 --- a/components/guns/http_scenario/gun.go +++ b/components/guns/http_scenario/gun.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "math/rand" + "net" "net/http" "net/http/httptrace" "net/http/httputil" @@ -249,6 +250,16 @@ func (g *ScenarioGun) prepareRequest(reqParts RequestParts) (*http.Request, erro req.Header.Set(k, v) } + if g.base.Config.SSL { + req.URL.Scheme = "https" + } else { + req.URL.Scheme = "http" + } + if req.Host == "" { + req.Host = getHostWithoutPort(g.base.Config.Target) + } + req.URL.Host = g.base.Config.TargetResolved + return req, err } @@ -354,3 +365,11 @@ func (g *ScenarioGun) reportErr(sample *netsample.Sample, err error) { sample.SetErr(err) g.base.Aggregator.Report(sample) } + +func getHostWithoutPort(target string) string { + host, _, err := net.SplitHostPort(target) + if err != nil { + host = target + } + return host +} diff --git a/components/guns/http_scenario/gun_test.go b/components/guns/http_scenario/gun_test.go index 73bc0ffe3..abfeb8e53 100644 --- a/components/guns/http_scenario/gun_test.go +++ b/components/guns/http_scenario/gun_test.go @@ -20,7 +20,7 @@ import ( func TestBaseGun_shoot(t *testing.T) { type fields struct { DebugLog bool - Config phttp.BaseGunConfig + Config phttp.GunConfig Connect func(ctx context.Context) error OnClose func() error Aggregator netsample.Aggregator diff --git a/components/guns/http_scenario/import.go b/components/guns/http_scenario/import.go index fb87ad1e6..2db46bd78 100644 --- a/components/guns/http_scenario/import.go +++ b/components/guns/http_scenario/import.go @@ -29,20 +29,22 @@ func (g *gunWrapper) Bind(a core.Aggregator, deps core.GunDeps) error { } func Import(fs afero.Fs) { - register.Gun("http/scenario", func(conf phttp.HTTPGunConfig) func() core.Gun { + register.Gun("http/scenario", func(conf phttp.GunConfig) func() core.Gun { targetResolved, _ := phttp.PreResolveTargetAddr(&conf.Client, conf.Target) - answLog := answlog.Init(conf.Base.AnswLog.Path, conf.Base.AnswLog.Enabled) + conf.TargetResolved = targetResolved + answLog := answlog.Init(conf.AnswLog.Path, conf.AnswLog.Enabled) return func() core.Gun { - gun := NewHTTPGun(conf, answLog, targetResolved) + gun := NewHTTPGun(conf, answLog) return WrapGun(gun) } }, phttp.DefaultHTTPGunConfig) - register.Gun("http2/scenario", func(conf phttp.HTTPGunConfig) func() (core.Gun, error) { + register.Gun("http2/scenario", func(conf phttp.GunConfig) func() (core.Gun, error) { targetResolved, _ := phttp.PreResolveTargetAddr(&conf.Client, conf.Target) - answLog := answlog.Init(conf.Base.AnswLog.Path, conf.Base.AnswLog.Enabled) + conf.TargetResolved = targetResolved + answLog := answlog.Init(conf.AnswLog.Path, conf.AnswLog.Enabled) return func() (core.Gun, error) { - gun, err := NewHTTP2Gun(conf, answLog, targetResolved) + gun, err := NewHTTP2Gun(conf, answLog) return WrapGun(gun), err } }, phttp.DefaultHTTP2GunConfig) diff --git a/components/guns/http_scenario/new.go b/components/guns/http_scenario/new.go index 8e47ee5aa..d605d3376 100644 --- a/components/guns/http_scenario/new.go +++ b/components/guns/http_scenario/new.go @@ -7,29 +7,21 @@ import ( "go.uber.org/zap" ) -func NewHTTPGun(conf phttp.HTTPGunConfig, answLog *zap.Logger, targetResolved string) *ScenarioGun { - return newScenarioGun(phttp.HTTP1ClientConstructor, conf, answLog, targetResolved) +func NewHTTPGun(conf phttp.GunConfig, answLog *zap.Logger) *ScenarioGun { + return newScenarioGun(phttp.HTTP1ClientConstructor, conf, answLog) } // NewHTTP2Gun return simple HTTP/2 gun that can shoot sequentially through one connection. -func NewHTTP2Gun(conf phttp.HTTPGunConfig, answLog *zap.Logger, targetResolved string) (*ScenarioGun, error) { +func NewHTTP2Gun(conf phttp.GunConfig, answLog *zap.Logger) (*ScenarioGun, error) { if !conf.SSL { // Open issue on github if you really need this feature. return nil, errors.New("HTTP/2.0 over TCP is not supported. Please leave SSL option true by default") } - return newScenarioGun(phttp.HTTP2ClientConstructor, conf, answLog, targetResolved), nil + return newScenarioGun(phttp.HTTP2ClientConstructor, conf, answLog), nil } -func newScenarioGun(clientConstructor phttp.ClientConstructor, cfg phttp.HTTPGunConfig, answLog *zap.Logger, targetResolved string) *ScenarioGun { - var wrappedConstructor = func(clientConfig phttp.ClientConfig, target string) phttp.Client { - return phttp.WrapClientHostResolving( - clientConstructor(cfg.Client, cfg.Target), - cfg, - targetResolved, - ) - } - +func newScenarioGun(clientConstructor phttp.ClientConstructor, cfg phttp.GunConfig, answLog *zap.Logger) *ScenarioGun { return &ScenarioGun{ - base: phttp.NewBaseGun(wrappedConstructor, cfg, answLog), + base: phttp.NewBaseGun(clientConstructor, cfg, answLog), } } diff --git a/components/phttp/import/import.go b/components/phttp/import/import.go index 2a9140b77..fc78607e0 100644 --- a/components/phttp/import/import.go +++ b/components/phttp/import/import.go @@ -16,24 +16,27 @@ func Import(fs afero.Fs) { scenarioGun.Import(fs) scenarioProvider.Import(fs) - register.Gun("http", func(conf phttp.HTTPGunConfig) func() core.Gun { + register.Gun("http", func(conf phttp.GunConfig) func() core.Gun { targetResolved, _ := phttp.PreResolveTargetAddr(&conf.Client, conf.Target) - answLog := answlog.Init(conf.Base.AnswLog.Path, conf.Base.AnswLog.Enabled) - return func() core.Gun { return phttp.WrapGun(phttp.NewHTTP1Gun(conf, answLog, targetResolved)) } + conf.TargetResolved = targetResolved + answLog := answlog.Init(conf.AnswLog.Path, conf.AnswLog.Enabled) + return func() core.Gun { return phttp.WrapGun(phttp.NewHTTP1Gun(conf, answLog)) } }, phttp.DefaultHTTPGunConfig) - register.Gun("http2", func(conf phttp.HTTPGunConfig) func() (core.Gun, error) { + register.Gun("http2", func(conf phttp.GunConfig) func() (core.Gun, error) { targetResolved, _ := phttp.PreResolveTargetAddr(&conf.Client, conf.Target) - answLog := answlog.Init(conf.Base.AnswLog.Path, conf.Base.AnswLog.Enabled) + conf.TargetResolved = targetResolved + answLog := answlog.Init(conf.AnswLog.Path, conf.AnswLog.Enabled) return func() (core.Gun, error) { - gun, err := phttp.NewHTTP2Gun(conf, answLog, targetResolved) + gun, err := phttp.NewHTTP2Gun(conf, answLog) return phttp.WrapGun(gun), err } }, phttp.DefaultHTTP2GunConfig) - register.Gun("connect", func(conf phttp.HTTPGunConfig) func() core.Gun { + register.Gun("connect", func(conf phttp.GunConfig) func() core.Gun { conf.Target, _ = phttp.PreResolveTargetAddr(&conf.Client, conf.Target) - answLog := answlog.Init(conf.Base.AnswLog.Path, conf.Base.AnswLog.Enabled) + conf.TargetResolved = conf.Target + answLog := answlog.Init(conf.AnswLog.Path, conf.AnswLog.Enabled) return func() core.Gun { return phttp.WrapGun(phttp.NewConnectGun(conf, answLog)) } diff --git a/lib/str/format_test.go b/lib/str/format_test.go index a6195992c..9d95a30b0 100644 --- a/lib/str/format_test.go +++ b/lib/str/format_test.go @@ -33,7 +33,6 @@ func TestMultiFormatString(t *testing.T) { } for k, v := range list { s := FormatString(v) - t.Log(s) if s != k { t.Errorf("Error: %v to %s,but %s", v, k, s) } diff --git a/tests/http_scenario/main_test.go b/tests/http_scenario/main_test.go index b0beacdf1..82c35bb25 100644 --- a/tests/http_scenario/main_test.go +++ b/tests/http_scenario/main_test.go @@ -72,10 +72,11 @@ func (s *GunSuite) SetupTest() { func (s *GunSuite) Test_SuccessScenario() { ctx := context.Background() log := zap.NewNop() - g := httpscenario.NewHTTPGun(phttp.HTTPGunConfig{ - Target: s.addr, - Client: phttp.ClientConfig{}, - }, log, s.addr) + g := httpscenario.NewHTTPGun(phttp.GunConfig{ + Target: s.addr, + TargetResolved: s.addr, + Client: phttp.ClientConfig{}, + }, log) gunDeps := core.GunDeps{Ctx: ctx, Log: log, PoolID: "pool_id", InstanceID: 1} aggr := &Aggregator{} From 32f96c66007d5b012311dbd2b79c92e38fae2fd7 Mon Sep 17 00:00:00 2001 From: Denis Mulin Date: Sat, 27 Apr 2024 15:16:02 +0300 Subject: [PATCH 6/8] grpc reflection metadata No description --- 3c551d4d5499fff815a67cd15bf452956057e256 Pull Request resolved: https://github.com/yandex/pandora/pull/188 --- components/guns/grpc/core.go | 18 ++--- components/guns/grpc/scenario/core.go | 22 +++--- tests/acceptance/config_model.go | 13 ++-- tests/acceptance/grpc_test.go | 107 ++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 24 deletions(-) diff --git a/components/guns/grpc/core.go b/components/guns/grpc/core.go index 251f8958b..c030a7949 100644 --- a/components/guns/grpc/core.go +++ b/components/guns/grpc/core.go @@ -43,13 +43,14 @@ type GrpcDialOptions struct { } type GunConfig struct { - Target string `validate:"required"` - ReflectPort int64 `config:"reflect_port"` - Timeout time.Duration `config:"timeout"` // grpc request timeout - TLS bool `config:"tls"` - DialOptions GrpcDialOptions `config:"dial_options"` - AnswLog AnswLogConfig `config:"answlog"` - SharedClient struct { + Target string `validate:"required"` + ReflectPort int64 `config:"reflect_port"` + ReflectMetadata metadata.MD `config:"reflect_metadata"` + Timeout time.Duration `config:"timeout"` // grpc request timeout + TLS bool `config:"tls"` + DialOptions GrpcDialOptions `config:"dial_options"` + AnswLog AnswLogConfig `config:"answlog"` + SharedClient struct { ClientNumber int `config:"client-number,omitempty"` Enabled bool `config:"enabled"` } `config:"shared-client,omitempty"` @@ -110,8 +111,7 @@ func (g *Gun) prepareMethodList(opts *warmup.Options) (map[string]desc.MethodDes } defer conn.Close() - meta := make(metadata.MD) - refCtx := metadata.NewOutgoingContext(context.Background(), meta) + refCtx := metadata.NewOutgoingContext(context.Background(), g.Conf.ReflectMetadata) refClient := grpcreflect.NewClientAuto(refCtx, conn) listServices, err := refClient.ListServices() if err != nil { diff --git a/components/guns/grpc/scenario/core.go b/components/guns/grpc/scenario/core.go index 68e078ac0..018c31f89 100644 --- a/components/guns/grpc/scenario/core.go +++ b/components/guns/grpc/scenario/core.go @@ -21,12 +21,13 @@ import ( const defaultTimeout = time.Second * 15 type GunConfig struct { - Target string `validate:"required"` - ReflectPort int64 `config:"reflect_port"` - Timeout time.Duration `config:"timeout"` // grpc request timeout - TLS bool `config:"tls"` - DialOptions GrpcDialOptions `config:"dial_options"` - AnswLog AnswLogConfig `config:"answlog"` + Target string `validate:"required"` + ReflectPort int64 `config:"reflect_port"` + ReflectMetadata metadata.MD `config:"reflect_metadata"` + Timeout time.Duration `config:"timeout"` // grpc request timeout + TLS bool `config:"tls"` + DialOptions GrpcDialOptions `config:"dial_options"` + AnswLog AnswLogConfig `config:"answlog"` } type GrpcDialOptions struct { @@ -57,10 +58,11 @@ func NewGun(conf GunConfig) *Gun { return &Gun{ templ: NewTextTemplater(), gun: &grpcgun.Gun{Conf: grpcgun.GunConfig{ - Target: conf.Target, - ReflectPort: conf.ReflectPort, - Timeout: conf.Timeout, - TLS: conf.TLS, + Target: conf.Target, + ReflectPort: conf.ReflectPort, + ReflectMetadata: conf.ReflectMetadata, + Timeout: conf.Timeout, + TLS: conf.TLS, DialOptions: grpcgun.GrpcDialOptions{ Authority: conf.DialOptions.Authority, Timeout: conf.DialOptions.Timeout, diff --git a/tests/acceptance/config_model.go b/tests/acceptance/config_model.go index a0ccd9e15..b16b3b6ef 100644 --- a/tests/acceptance/config_model.go +++ b/tests/acceptance/config_model.go @@ -1,5 +1,7 @@ package acceptance +import "google.golang.org/grpc/metadata" + type PandoraConfigLog struct { Level string `yaml:"level"` } @@ -11,11 +13,12 @@ type PandoraConfigMonitoring struct { ExpVar PandoraConfigMonitoringExpVar `yaml:"expvar"` } type PandoraConfigGRPCGun struct { - Type string `yaml:"type"` - Target string `yaml:"target"` - TLS bool `yaml:"tls"` - ReflectPort *int64 `yaml:"reflect_port,omitempty"` - SharedClient struct { + Type string `yaml:"type"` + Target string `yaml:"target"` + TLS bool `yaml:"tls"` + ReflectPort *int64 `yaml:"reflect_port,omitempty"` + ReflectMetadata *metadata.MD `yaml:"reflect_metadata,omitempty"` + SharedClient struct { ClientNumber int `yaml:"client-number,omitempty"` Enabled bool `yaml:"enabled"` } `yaml:"shared-client,omitempty"` diff --git a/tests/acceptance/grpc_test.go b/tests/acceptance/grpc_test.go index 491b327c9..6b538fc19 100644 --- a/tests/acceptance/grpc_test.go +++ b/tests/acceptance/grpc_test.go @@ -2,12 +2,14 @@ package acceptance import ( "context" + "fmt" "log/slog" "net" "os" "testing" "time" + "github.com/pkg/errors" "github.com/spf13/afero" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -21,6 +23,7 @@ import ( "github.com/yandex/pandora/lib/testutil" "go.uber.org/zap" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/reflection" "gopkg.in/yaml.v2" ) @@ -116,6 +119,89 @@ func TestCheckGRPCReflectServer(t *testing.T) { require.NoError(t, err) require.Equal(t, int64(8), st.Hello) }) + + t.Run("reflect with custom metadata", func(t *testing.T) { + metadataKey := "testKey" + metadataValue := "testValue" + wrongMDValuesLengthError := errors.New("wrong metadata values length") + wrongMDValueError := errors.New("wrong metadata value") + metadataChecker := func(ctx context.Context) (context.Context, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, wrongMDValuesLengthError + } + vals := md.Get(metadataKey) + if len(vals) != 1 { + return nil, wrongMDValuesLengthError + } + if vals[0] != metadataValue { + return nil, wrongMDValueError + } + return ctx, nil + } + grpcServer := grpc.NewServer( + grpc.UnaryInterceptor(MetadataServerInterceptor(metadataChecker)), + grpc.StreamInterceptor(MetadataServerStreamInterceptor(metadataChecker))) + srv := server.NewServer(logger, time.Now().UnixNano()) + server.RegisterTargetServiceServer(grpcServer, srv) + grpcAddress := "localhost:18888" + reflection.Register(grpcServer) + l, err := net.Listen("tcp", grpcAddress) + require.NoError(t, err) + go func() { + err = grpcServer.Serve(l) + require.NoError(t, err) + }() + + defer func() { + grpcServer.Stop() + }() + + cases := []struct { + name string + conf *cli.CliConfig + err error + }{ + { + name: "success", + conf: parseFileContentToCliConfig(t, baseFile, func(c *PandoraConfigGRPC) { + md := metadata.New(map[string]string{metadataKey: metadataValue}) + c.Pools[0].Gun.ReflectMetadata = &md + }), + }, + { + name: "no metadata", + conf: parseFileContentToCliConfig(t, baseFile, nil), + err: wrongMDValuesLengthError, + }, + { + name: "wrong metadata value", + conf: parseFileContentToCliConfig(t, baseFile, func(c *PandoraConfigGRPC) { + md := metadata.New(map[string]string{metadataKey: "wrong-value"}) + c.Pools[0].Gun.ReflectMetadata = &md + }), + err: wrongMDValueError, + }, + } + + for _, cc := range cases { + t.Run(cc.name, func(t *testing.T) { + require.Equal(t, 1, len(cc.conf.Engine.Pools)) + aggr := &aggregator{} + cc.conf.Engine.Pools[0].Aggregator = aggr + + pandora := engine.New(pandoraLogger, pandoraMetrics, cc.conf.Engine) + err = pandora.Run(context.Background()) + + if cc.err == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), cc.err.Error()) + } + }) + } + }) } func TestGrpcGunSuite(t *testing.T) { @@ -211,3 +297,24 @@ func parseFileContentToCliConfig(t *testing.T, baseFile []byte, overwrite func(c return decodeConfig(t, mapCfg) } + +func MetadataServerInterceptor(metadataChecker func(ctx context.Context) (context.Context, error)) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + ctx, err = metadataChecker(ctx) + if err != nil { + return nil, fmt.Errorf("metadata checker: %w", err) + } + return handler(ctx, req) + } +} + +func MetadataServerStreamInterceptor(metadataChecker func(ctx context.Context) (context.Context, error)) grpc.StreamServerInterceptor { + return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) (err error) { + ctx := ss.Context() + ctx, err = metadataChecker(ctx) + if err != nil { + return fmt.Errorf("metadata checker: %w", err) + } + return handler(srv, ss) + } +} From 40815db2e7b25296a8b87adbb9d53cb20cff9555 Mon Sep 17 00:00:00 2001 From: sabevzenko Date: Sat, 27 Apr 2024 15:16:13 +0300 Subject: [PATCH 7/8] grpc scenario err 61bcfb6f21a0647117de24e3b6230d5f14ec118a --- cli/cli.go | 3 ++- components/guns/grpc/core.go | 20 ++++++++++++++------ components/guns/grpc/scenario/core.go | 22 +++++----------------- components/guns/http_scenario/gun.go | 2 +- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index a5c0cd01f..a5caee41f 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -25,7 +25,7 @@ import ( "go.uber.org/zap/zapcore" ) -const Version = "0.5.23" +const Version = "0.5.24.alpha1" const defaultConfigFile = "load" const stdinConfigSelector = "-" @@ -218,6 +218,7 @@ func readConfig(args []string) *CliConfig { } } + log.Info("Pandora version", zap.String("version", Version)) if useStdinConfig { v.SetConfigType("yaml") configBuffer, err := ioutil.ReadAll(bufio.NewReader(os.Stdin)) diff --git a/components/guns/grpc/core.go b/components/guns/grpc/core.go index c030a7949..08f2ab8ad 100644 --- a/components/guns/grpc/core.go +++ b/components/guns/grpc/core.go @@ -238,27 +238,35 @@ func (g *Gun) shoot(ammo *ammo.Ammo) { g.GunDeps.Log.Error("response error", zap.Error(err)) } + g.Answ(&method, message, ammo.Metadata, out, grpcErr, code) +} + +func (g *Gun) Answ(method *desc.MethodDescriptor, message *dynamic.Message, metadata map[string]string, out proto.Message, grpcErr error, code int) { if g.Conf.AnswLog.Enabled { switch g.Conf.AnswLog.Filter { case "all": - g.AnswLogging(g.AnswLog, &method, message, out, grpcErr) + g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr) case "warning": if code >= 400 { - g.AnswLogging(g.AnswLog, &method, message, out, grpcErr) + g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr) } case "error": if code >= 500 { - g.AnswLogging(g.AnswLog, &method, message, out, grpcErr) + g.AnswLogging(g.AnswLog, method, message, metadata, out, grpcErr) } } } } -func (g *Gun) AnswLogging(logger *zap.Logger, method *desc.MethodDescriptor, request proto.Message, response proto.Message, grpcErr error) { - logger.Debug("Request:", zap.Stringer("method", method), zap.Stringer("message", request)) - logger.Debug("Response:", zap.Stringer("resp", response), zap.Error(grpcErr)) +func (g *Gun) AnswLogging(logger *zap.Logger, method *desc.MethodDescriptor, request proto.Message, metadata map[string]string, response proto.Message, grpcErr error) { + logger.Debug("Request:", zap.Stringer("method", method), zap.Stringer("message", request), zap.Any("metadata", metadata)) + if response != nil { + logger.Debug("Response:", zap.Stringer("resp", response), zap.Error(grpcErr)) + } else { + logger.Debug("Response:", zap.String("resp", "empty"), zap.Error(grpcErr)) + } } func (g *Gun) makeConnect() (conn *grpc.ClientConn, err error) { diff --git a/components/guns/grpc/scenario/core.go b/components/guns/grpc/scenario/core.go index 018c31f89..bed051bfe 100644 --- a/components/guns/grpc/scenario/core.go +++ b/components/guns/grpc/scenario/core.go @@ -118,6 +118,9 @@ func (g *Gun) shoot(ammo *Scenario, templateVars map[string]any) error { requestVars := map[string]any{} templateVars["request"] = requestVars + if g.gun.DebugLog { + g.gun.GunDeps.Log.Debug("Source variables", zap.Any("variables", templateVars)) + } startAt := time.Now() for _, call := range ammo.Calls { @@ -156,7 +159,7 @@ func (g *Gun) shootStep(step *Call, sample *netsample.Sample, ammoName string, t } preprocVars = mergeMaps(preprocVars, pp) if g.gun.DebugLog { - g.gun.GunDeps.Log.Debug("PreparePreprocessor variables", zap.Any(fmt.Sprintf(".resuest.%s.preprocessor", step.Name), pp)) + g.gun.GunDeps.Log.Debug("PreparePreprocessor variables", zap.Any(fmt.Sprintf(".request.%s.preprocessor", step.Name), pp)) } } stepVars["preprocessor"] = preprocVars @@ -200,22 +203,7 @@ func (g *Gun) shootStep(step *Call, sample *netsample.Sample, ammoName string, t g.gun.GunDeps.Log.Error("response error", zap.Error(err)) } - if g.gun.Conf.AnswLog.Enabled { - switch g.gun.Conf.AnswLog.Filter { - case "all": - g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr) - - case "warning": - if code >= 400 { - g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr) - } - - case "error": - if code >= 500 { - g.gun.AnswLogging(g.gun.AnswLog, &method, message, out, grpcErr) - } - } - } + g.gun.Answ(&method, message, step.Metadata, out, grpcErr, code) for _, postProcessor := range step.Postprocessors { pp, err := postProcessor.Process(out, code) diff --git a/components/guns/http_scenario/gun.go b/components/guns/http_scenario/gun.go index 9b173a65b..1bdaf2f8a 100644 --- a/components/guns/http_scenario/gun.go +++ b/components/guns/http_scenario/gun.go @@ -151,7 +151,7 @@ func (g *ScenarioGun) shootStep(step Request, sample *netsample.Sample, ammoName var dumpErr error reqBytes, dumpErr = httputil.DumpRequestOut(req, true) if dumpErr != nil { - g.base.Log.Error("Error dumping request: %s", zap.Error(dumpErr)) + g.base.Log.Error("Error dumping request:", zap.Error(dumpErr)) } } From a926b553974d224f71a99c7fa3e002fdb7714ca2 Mon Sep 17 00:00:00 2001 From: sabevzenko Date: Sat, 27 Apr 2024 17:58:21 +0300 Subject: [PATCH 8/8] v0.5.24 e916017134d40bbc46361dd56f9a456c6ea413d2 --- .changes/v0.5.24.md | 9 +++++++++ .mapping.json | 1 + CHANGELOG.md | 10 ++++++++++ cli/cli.go | 2 +- go.mod | 22 ++++++++++----------- go.sum | 37 +++++++++++++++++------------------ tests/acceptance/grpc_test.go | 2 +- 7 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 .changes/v0.5.24.md diff --git a/.changes/v0.5.24.md b/.changes/v0.5.24.md new file mode 100644 index 000000000..58919b793 --- /dev/null +++ b/.changes/v0.5.24.md @@ -0,0 +1,9 @@ +## v0.5.24 - 2024-04-27 +### Added +* HCL scenario: add support for "locals" block in hcl +* grpc/scenario: debug logs +* grpc generator: reflection metadata +### Changed +* discard_overflow default value =true +### Fixed +* http generator: fix answlog error diff --git a/.mapping.json b/.mapping.json index 2662c041c..e903f7fbc 100644 --- a/.mapping.json +++ b/.mapping.json @@ -21,6 +21,7 @@ ".changes/v0.5.21.md":"load/projects/pandora/.changes/v0.5.21.md", ".changes/v0.5.22.md":"load/projects/pandora/.changes/v0.5.22.md", ".changes/v0.5.23.md":"load/projects/pandora/.changes/v0.5.23.md", + ".changes/v0.5.24.md":"load/projects/pandora/.changes/v0.5.24.md", ".changie.yaml":"load/projects/pandora/.changie.yaml", ".github/workflows/release.yml":"load/projects/pandora/.github/workflows/release.yml", ".github/workflows/test.yml":"load/projects/pandora/.github/workflows/test.yml", diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c9d570d..a5ab3d30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## v0.5.24 - 2024-04-27 +### Added +* HCL scenario: add support for "locals" block in hcl +* grpc/scenario: debug logs +* grpc generator: reflection metadata +### Changed +* discard_overflow default value =true +### Fixed +* http generator: fix answlog error + ## v0.5.23 - 2024-04-16 ### Added * function for generate random values in scenario diff --git a/cli/cli.go b/cli/cli.go index a5caee41f..1171f0163 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -25,7 +25,7 @@ import ( "go.uber.org/zap/zapcore" ) -const Version = "0.5.24.alpha1" +const Version = "0.5.24" const defaultConfigFile = "load" const stdinConfigSelector = "-" diff --git a/go.mod b/go.mod index 4f1ad08a6..7b6e4b7d8 100644 --- a/go.mod +++ b/go.mod @@ -20,15 +20,16 @@ require ( github.com/json-iterator/go v1.1.12 github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 github.com/pkg/errors v0.9.1 - github.com/spf13/afero v1.9.5 + github.com/spf13/afero v1.10.0 github.com/spf13/viper v1.16.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 + github.com/zclconf/go-cty v1.13.2 go.uber.org/atomic v1.11.0 - go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + go.uber.org/zap v1.27.0 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/net v0.22.0 - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 - google.golang.org/grpc v1.61.0 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 + google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.33.0 gopkg.in/bluesuncorp/validator.v9 v9.10.0 gopkg.in/yaml.v2 v2.4.0 @@ -38,7 +39,7 @@ require ( github.com/PaesslerAG/gval v1.2.1 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect - github.com/bufbuild/protocompile v0.8.0 // indirect + github.com/bufbuild/protocompile v0.9.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/frankban/quicktest v1.14.6 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -62,15 +63,12 @@ require ( github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c // indirect - github.com/stretchr/objx v0.5.1 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect - github.com/zclconf/go-cty v1.13.2 // indirect - go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index c6cc6001e..4481af1f4 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/bufbuild/protocompile v0.8.0 h1:9Kp1q6OkS9L4nM3FYbr8vlJnEwtbpDPQlQOVXfR+78s= -github.com/bufbuild/protocompile v0.8.0/go.mod h1:+Etjg4guZoAqzVk2czwEQP12yaxLJ8DxuqCJ9qHdH94= +github.com/bufbuild/protocompile v0.9.0 h1:DI8qLG5PEO0Mu1Oj51YFPqtx6I3qYXUAhJVJ/IzAVl0= +github.com/bufbuild/protocompile v0.9.0/go.mod h1:s89m1O8CqSYpyE/YaSGtg1r1YFMF5nLTwh4vlj6O444= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -216,8 +216,8 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -229,8 +229,8 @@ github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1Fof github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= -github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -238,10 +238,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -262,8 +261,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -281,8 +280,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -464,8 +463,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -528,8 +527,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 h1:IR+hp6ypxjH24bkMfEJ0yHR21+gwPWdV+/IBrPQyn3k= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -546,8 +545,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/tests/acceptance/grpc_test.go b/tests/acceptance/grpc_test.go index 6b538fc19..1c548c2cf 100644 --- a/tests/acceptance/grpc_test.go +++ b/tests/acceptance/grpc_test.go @@ -311,7 +311,7 @@ func MetadataServerInterceptor(metadataChecker func(ctx context.Context) (contex func MetadataServerStreamInterceptor(metadataChecker func(ctx context.Context) (context.Context, error)) grpc.StreamServerInterceptor { return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) (err error) { ctx := ss.Context() - ctx, err = metadataChecker(ctx) + _, err = metadataChecker(ctx) if err != nil { return fmt.Errorf("metadata checker: %w", err) }