From 35edfd0f07af2f79ae046f81fb2440fc68fce0f4 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Wed, 5 Feb 2025 21:00:16 +0800 Subject: [PATCH] refactor: move boomer to github.com/httprunner/boomer --- go.mod | 23 +- go.sum | 464 ------ hrp/internal/builtin/utils.go | 73 - hrp/internal/version/VERSION | 2 +- hrp/pkg/boomer/README.md | 5 - hrp/pkg/boomer/boomer.go | 613 ------- hrp/pkg/boomer/boomer_test.go | 146 -- hrp/pkg/boomer/client_grpc.go | 336 ---- hrp/pkg/boomer/client_grpc_test.go | 1 - hrp/pkg/boomer/data/data.go | 61 - hrp/pkg/boomer/data/x509/README.md | 6 - hrp/pkg/boomer/data/x509/ca_cert.pem | 34 - hrp/pkg/boomer/data/x509/ca_key.pem | 52 - hrp/pkg/boomer/data/x509/client_ca_cert.pem | 34 - hrp/pkg/boomer/data/x509/client_ca_key.pem | 52 - hrp/pkg/boomer/data/x509/client_cert.pem | 32 - hrp/pkg/boomer/data/x509/client_key.pem | 51 - hrp/pkg/boomer/data/x509/create.sh | 69 - hrp/pkg/boomer/data/x509/openssl.cnf | 28 - hrp/pkg/boomer/data/x509/server_cert.pem | 32 - hrp/pkg/boomer/data/x509/server_key.pem | 51 - hrp/pkg/boomer/grpc/messager/messager.pb.go | 589 ------- .../boomer/grpc/messager/messager_grpc.pb.go | 212 --- hrp/pkg/boomer/grpc/proto/messager.proto | 45 - hrp/pkg/boomer/hrp/boomer.go | 445 ------ hrp/pkg/boomer/hrp/boomer_server.go | 381 ----- hrp/pkg/boomer/hrp/boomer_test.go | 32 - hrp/pkg/boomer/hrp/cli/boom.go | 147 -- hrp/pkg/boomer/hrp/cli/main.go | 22 - hrp/pkg/boomer/message.go | 55 - hrp/pkg/boomer/message_test.go | 1 - hrp/pkg/boomer/output.go | 645 -------- hrp/pkg/boomer/output_test.go | 104 -- hrp/pkg/boomer/ratelimiter.go | 230 --- hrp/pkg/boomer/ratelimiter_test.go | 102 -- hrp/pkg/boomer/runner.go | 1417 ----------------- hrp/pkg/boomer/runner_test.go | 552 ------- hrp/pkg/boomer/server_grpc.go | 577 ------- hrp/pkg/boomer/server_grpc_test.go | 1 - hrp/pkg/boomer/stats.go | 302 ---- hrp/pkg/boomer/stats_test.go | 215 --- hrp/pkg/boomer/task.go | 13 - hrp/pkg/boomer/ulimit.go | 33 - hrp/pkg/boomer/ulimit_windows.go | 12 - hrp/pkg/boomer/utils.go | 150 -- hrp/pkg/boomer/utils_test.go | 72 - 46 files changed, 3 insertions(+), 8516 deletions(-) delete mode 100644 hrp/pkg/boomer/README.md delete mode 100644 hrp/pkg/boomer/boomer.go delete mode 100644 hrp/pkg/boomer/boomer_test.go delete mode 100644 hrp/pkg/boomer/client_grpc.go delete mode 100644 hrp/pkg/boomer/client_grpc_test.go delete mode 100644 hrp/pkg/boomer/data/data.go delete mode 100644 hrp/pkg/boomer/data/x509/README.md delete mode 100644 hrp/pkg/boomer/data/x509/ca_cert.pem delete mode 100644 hrp/pkg/boomer/data/x509/ca_key.pem delete mode 100644 hrp/pkg/boomer/data/x509/client_ca_cert.pem delete mode 100644 hrp/pkg/boomer/data/x509/client_ca_key.pem delete mode 100644 hrp/pkg/boomer/data/x509/client_cert.pem delete mode 100644 hrp/pkg/boomer/data/x509/client_key.pem delete mode 100755 hrp/pkg/boomer/data/x509/create.sh delete mode 100644 hrp/pkg/boomer/data/x509/openssl.cnf delete mode 100644 hrp/pkg/boomer/data/x509/server_cert.pem delete mode 100644 hrp/pkg/boomer/data/x509/server_key.pem delete mode 100644 hrp/pkg/boomer/grpc/messager/messager.pb.go delete mode 100644 hrp/pkg/boomer/grpc/messager/messager_grpc.pb.go delete mode 100644 hrp/pkg/boomer/grpc/proto/messager.proto delete mode 100644 hrp/pkg/boomer/hrp/boomer.go delete mode 100644 hrp/pkg/boomer/hrp/boomer_server.go delete mode 100644 hrp/pkg/boomer/hrp/boomer_test.go delete mode 100644 hrp/pkg/boomer/hrp/cli/boom.go delete mode 100644 hrp/pkg/boomer/hrp/cli/main.go delete mode 100644 hrp/pkg/boomer/message.go delete mode 100644 hrp/pkg/boomer/message_test.go delete mode 100644 hrp/pkg/boomer/output.go delete mode 100644 hrp/pkg/boomer/output_test.go delete mode 100644 hrp/pkg/boomer/ratelimiter.go delete mode 100644 hrp/pkg/boomer/ratelimiter_test.go delete mode 100644 hrp/pkg/boomer/runner.go delete mode 100644 hrp/pkg/boomer/runner_test.go delete mode 100644 hrp/pkg/boomer/server_grpc.go delete mode 100644 hrp/pkg/boomer/server_grpc_test.go delete mode 100644 hrp/pkg/boomer/stats.go delete mode 100644 hrp/pkg/boomer/stats_test.go delete mode 100644 hrp/pkg/boomer/task.go delete mode 100644 hrp/pkg/boomer/ulimit.go delete mode 100644 hrp/pkg/boomer/ulimit_windows.go delete mode 100644 hrp/pkg/boomer/utils.go delete mode 100644 hrp/pkg/boomer/utils_test.go diff --git a/go.mod b/go.mod index cbff37b3..1cd6b4c2 100644 --- a/go.mod +++ b/go.mod @@ -23,31 +23,21 @@ require ( github.com/json-iterator/go v1.1.12 github.com/maja42/goval v1.2.1 github.com/mitchellh/mapstructure v1.5.0 - github.com/olekukonko/tablewriter v0.0.5 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.13.0 github.com/rs/zerolog v1.30.0 github.com/satori/go.uuid v1.2.0 - github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.9.0 golang.org/x/net v0.26.0 - golang.org/x/oauth2 v0.8.0 golang.org/x/text v0.16.0 - google.golang.org/grpc v1.57.0 - google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute v1.23.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect @@ -55,7 +45,6 @@ require ( github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-errors/errors v1.4.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -80,8 +69,6 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/miekg/dns v1.1.57 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -91,23 +78,16 @@ require ( github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/quic-go/quic-go v0.40.1-0.20231203135336-87ef8ec48d55 // indirect - github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tadglines/go-pkgs v0.0.0-20210623144937-b983b20f54f9 // indirect - github.com/tklauser/go-sysconf v0.3.10 // indirect - github.com/tklauser/numcpus v0.5.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect go.uber.org/mock v0.3.0 // indirect golang.org/x/arch v0.8.0 // indirect @@ -119,8 +99,9 @@ require ( golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gvisor.dev/gvisor v0.0.0-20240405191320-0878b34101b5 // indirect howett.net/plist v1.0.0 // indirect software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect diff --git a/go.sum b/go.sum index f4d92d21..692c28a6 100644 --- a/go.sum +++ b/go.sum @@ -1,79 +1,24 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.byted.org/iesqa/ghdc v0.0.0-20241009025217-ecb76cf5bd27 h1:+wNJiEXXIUP6luKJRA4tfwDqfnWUON6LIopKD9tvUns= code.byted.org/iesqa/ghdc v0.0.0-20241009025217-ecb76cf5bd27/go.mod h1:C2kq6TTE+JAOnqDorSwae1MQzRuex03RshuSUC2U/FY= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 h1:+tu3HOoMXB7RXEINRVIpxJCT+KdYiI7LAEAUrOw3dIU= github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZdiDllfyYH5l5OkAaZtk7VkWe89bPJFmnDBNHxg= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -87,10 +32,6 @@ github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMS github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 h1:1NyRx2f4W4WBRyg0Kys0ZbaNmDDzZ2R/C7DTi+bbsJ0= github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380/go.mod h1:thX175TtLTzLj3p7N/Q9IiKZ7NF+p72cvL91emV0hzo= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -106,21 +47,8 @@ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -140,76 +68,26 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE= @@ -218,13 +96,10 @@ github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+ github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.4.10 h1:xUbmA4jC6Dq163/fWcp8P3JuHilrHHMLNRxzGQJ9hNk= github.com/hashicorp/go-plugin v1.4.10/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/httprunner/funplugin v0.5.5 h1:VU1a6kj1AsJ/ucIhhI5NLHXOP4xnW2JGgk50vBV3Zis= github.com/httprunner/funplugin v0.5.5/go.mod h1:YZzBBSOSdLZEpHZz0P2E5SOQ+o1+Fbn30oWS4RGHBz0= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= @@ -240,24 +115,12 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -283,11 +146,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= @@ -298,17 +156,11 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= @@ -320,44 +172,14 @@ github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/quic-go v0.40.1-0.20231203135336-87ef8ec48d55 h1:I4N3ZRnkZPbDN935Tg8QDf8fRpHp3bZ0U0/L42jBgNE= github.com/quic-go/quic-go v0.40.1-0.20231203135336-87ef8ec48d55/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= @@ -368,11 +190,6 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= @@ -382,14 +199,11 @@ github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/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.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= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= @@ -401,354 +215,86 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tadglines/go-pkgs v0.0.0-20210623144937-b983b20f54f9 h1:aeN+ghOV0b2VCmKKO3gqnDQ8mLbpABZgRR2FVYx4ouI= github.com/tadglines/go-pkgs v0.0.0-20210623144937-b983b20f54f9/go.mod h1:roo6cZ/uqpwKMuvPG0YmzI5+AmUiMWfjCBZpGXqbTxE= -github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A= -github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -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= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -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= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -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= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -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= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -757,19 +303,9 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gvisor.dev/gvisor v0.0.0-20240405191320-0878b34101b5 h1:DOUDfNS+CFMM46k18FRF5k/0yz5NhZYMiUQxf4xglIU= gvisor.dev/gvisor v0.0.0-20240405191320-0878b34101b5/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= diff --git a/hrp/internal/builtin/utils.go b/hrp/internal/builtin/utils.go index 2fae638d..f322a04b 100644 --- a/hrp/internal/builtin/utils.go +++ b/hrp/internal/builtin/utils.go @@ -7,7 +7,6 @@ import ( "crypto/hmac" "crypto/md5" "crypto/sha256" - "encoding/binary" "encoding/csv" builtinJSON "encoding/json" "fmt" @@ -273,78 +272,6 @@ func GetFileNameWithoutExtension(path string) string { return base[0 : len(base)-len(ext)] } -func Bytes2File(data []byte, filename string) error { - file, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o755) - defer file.Close() - if err != nil { - log.Error().Err(err).Msg("failed to generate file") - } - count, err := file.Write(data) - if err != nil { - return err - } - log.Info().Msg(fmt.Sprintf("write file %s len: %d \n", filename, count)) - return nil -} - -func Float32ToByte(v float32) []byte { - bits := math.Float32bits(v) - bytes := make([]byte, 4) - binary.LittleEndian.PutUint32(bytes, bits) - return bytes -} - -func ByteToFloat32(v []byte) float32 { - bits := binary.LittleEndian.Uint32(v) - return math.Float32frombits(bits) -} - -func Float64ToByte(v float64) []byte { - bits := math.Float64bits(v) - bts := make([]byte, 8) - binary.LittleEndian.PutUint64(bts, bits) - return bts -} - -func ByteToFloat64(v []byte) float64 { - bits := binary.LittleEndian.Uint64(v) - return math.Float64frombits(bits) -} - -func Int64ToBytes(n int64) []byte { - bytesBuf := bytes.NewBuffer([]byte{}) - _ = binary.Write(bytesBuf, binary.BigEndian, n) - return bytesBuf.Bytes() -} - -func BytesToInt64(bys []byte) (data int64) { - byteBuff := bytes.NewBuffer(bys) - _ = binary.Read(byteBuff, binary.BigEndian, &data) - return -} - -func SplitInteger(m, n int) (ints []int) { - quotient := m / n - remainder := m % n - if remainder >= 0 { - for i := 0; i < n-remainder; i++ { - ints = append(ints, quotient) - } - for i := 0; i < remainder; i++ { - ints = append(ints, quotient+1) - } - return - } else if remainder < 0 { - for i := 0; i < -remainder; i++ { - ints = append(ints, quotient-1) - } - for i := 0; i < n+remainder; i++ { - ints = append(ints, quotient) - } - } - return -} - func sha256HMAC(key []byte, data []byte) []byte { mac := hmac.New(sha256.New, key) mac.Write(data) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index dbadf32d..28cdc474 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2502052038 +v5.0.0+2502052100 diff --git a/hrp/pkg/boomer/README.md b/hrp/pkg/boomer/README.md deleted file mode 100644 index 91065761..00000000 --- a/hrp/pkg/boomer/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# boomer - -This module is initially forked from [myzhan/boomer@v1.6.0] and made a lot of changes. - -[myzhan/boomer@v1.6.0]: https://github.com/myzhan/boomer/tree/v1.6.0 diff --git a/hrp/pkg/boomer/boomer.go b/hrp/pkg/boomer/boomer.go deleted file mode 100644 index baac35e3..00000000 --- a/hrp/pkg/boomer/boomer.go +++ /dev/null @@ -1,613 +0,0 @@ -package boomer - -import ( - "math" - "os" - "os/signal" - "syscall" - "time" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" - "golang.org/x/net/context" - - "github.com/httprunner/httprunner/v4/hrp/internal/json" -) - -// Mode is the running mode of boomer, both standalone and distributed are supported. -type Mode int - -const ( - // DistributedMasterMode requires being connected by each worker. - DistributedMasterMode Mode = iota - // DistributedWorkerMode requires connecting to a master. - DistributedWorkerMode - // StandaloneMode will run without a master. - StandaloneMode -) - -// A Boomer is used to run tasks. -type Boomer struct { - masterHost string - masterPort int - mode Mode - - localRunner *localRunner - workerRunner *workerRunner - masterRunner *masterRunner - - testcasePath []string - - cpuProfile string - cpuProfileDuration time.Duration - - memoryProfile string - memoryProfileDuration time.Duration - - disableKeepalive bool - disableCompression bool -} - -type Profile struct { - SpawnCount int64 `json:"spawn-count,omitempty" yaml:"spawn-count,omitempty" mapstructure:"spawn-count,omitempty"` - SpawnRate float64 `json:"spawn-rate,omitempty" yaml:"spawn-rate,omitempty" mapstructure:"spawn-rate,omitempty"` - RunTime int64 `json:"run-time,omitempty" yaml:"run-time,omitempty" mapstructure:"run-time,omitempty"` - MaxRPS int64 `json:"max-rps,omitempty" yaml:"max-rps,omitempty" mapstructure:"max-rps,omitempty"` - LoopCount int64 `json:"loop-count,omitempty" yaml:"loop-count,omitempty" mapstructure:"loop-count,omitempty"` - RequestIncreaseRate string `json:"request-increase-rate,omitempty" yaml:"request-increase-rate,omitempty" mapstructure:"request-increase-rate,omitempty"` - MemoryProfile string `json:"memory-profile,omitempty" yaml:"memory-profile,omitempty" mapstructure:"memory-profile,omitempty"` - MemoryProfileDuration time.Duration `json:"memory-profile-duration,omitempty" yaml:"memory-profile-duration,omitempty" mapstructure:"memory-profile-duration,omitempty"` - CPUProfile string `json:"cpu-profile,omitempty" yaml:"cpu-profile,omitempty" mapstructure:"cpu-profile,omitempty"` - CPUProfileDuration time.Duration `json:"cpu-profile-duration,omitempty" yaml:"cpu-profile-duration,omitempty" mapstructure:"cpu-profile-duration,omitempty"` - PrometheusPushgatewayURL string `json:"prometheus-gateway,omitempty" yaml:"prometheus-gateway,omitempty" mapstructure:"prometheus-gateway,omitempty"` - DisableConsoleOutput bool `json:"disable-console-output,omitempty" yaml:"disable-console-output,omitempty" mapstructure:"disable-console-output,omitempty"` - DisableCompression bool `json:"disable-compression,omitempty" yaml:"disable-compression,omitempty" mapstructure:"disable-compression,omitempty"` - DisableKeepalive bool `json:"disable-keepalive,omitempty" yaml:"disable-keepalive,omitempty" mapstructure:"disable-keepalive,omitempty"` -} - -func NewProfile() *Profile { - return &Profile{ - SpawnCount: 1, - SpawnRate: 1, - MaxRPS: -1, - LoopCount: -1, - RequestIncreaseRate: "-1", - CPUProfileDuration: 30 * time.Second, - MemoryProfileDuration: 30 * time.Second, - } -} - -func (b *Boomer) GetProfile() *Profile { - switch b.mode { - case DistributedMasterMode: - return b.masterRunner.profile - case DistributedWorkerMode: - return b.workerRunner.profile - default: - return b.localRunner.profile - } -} - -func (b *Boomer) SetProfile(profile *Profile) { - switch b.mode { - case DistributedMasterMode: - b.masterRunner.profile = profile - case DistributedWorkerMode: - b.workerRunner.profile = profile - default: - b.localRunner.profile = profile - } -} - -// SetMode only accepts boomer.DistributedMasterMode、boomer.DistributedWorkerMode and boomer.StandaloneMode. -func (b *Boomer) SetMode(mode Mode) { - switch mode { - case DistributedMasterMode: - b.mode = DistributedMasterMode - case DistributedWorkerMode: - b.mode = DistributedWorkerMode - case StandaloneMode: - b.mode = StandaloneMode - default: - log.Error().Err(errors.New("Invalid mode, ignored!")) - } -} - -// GetMode returns boomer operating mode -func (b *Boomer) GetMode() string { - switch b.mode { - case DistributedMasterMode: - return "master" - case DistributedWorkerMode: - return "worker" - case StandaloneMode: - return "standalone" - default: - log.Error().Err(errors.New("Invalid mode, ignored!")) - return "" - } -} - -// NewStandaloneBoomer returns a new Boomer, which can run without master. -func NewStandaloneBoomer(spawnCount int64, spawnRate float64) *Boomer { - return &Boomer{ - mode: StandaloneMode, - localRunner: newLocalRunner(spawnCount, spawnRate), - } -} - -// NewMasterBoomer returns a new Boomer. -func NewMasterBoomer(masterBindHost string, masterBindPort int) *Boomer { - return &Boomer{ - masterRunner: newMasterRunner(masterBindHost, masterBindPort), - mode: DistributedMasterMode, - } -} - -// NewWorkerBoomer returns a new Boomer. -func NewWorkerBoomer(masterHost string, masterPort int) *Boomer { - return &Boomer{ - workerRunner: newWorkerRunner(masterHost, masterPort), - masterHost: masterHost, - masterPort: masterPort, - mode: DistributedWorkerMode, - } -} - -// SetAutoStart auto start to load testing -func (b *Boomer) SetAutoStart() { - b.masterRunner.autoStart = true -} - -// RunMaster start to run master runner -func (b *Boomer) RunMaster() { - b.masterRunner.run() -} - -// RunWorker start to run worker runner -func (b *Boomer) RunWorker() { - b.workerRunner.run() -} - -// TestCaseBytesChan gets test case bytes chan -func (b *Boomer) TestCaseBytesChan() chan []byte { - return b.masterRunner.testCaseBytesChan -} - -func (b *Boomer) GetTestCaseBytes() []byte { - switch b.mode { - case DistributedMasterMode: - return b.masterRunner.testCasesBytes - case DistributedWorkerMode: - return b.workerRunner.testCasesBytes - default: - return nil - } -} - -func ProfileToBytes(profile *Profile) []byte { - profileBytes, err := json.Marshal(profile) - if err != nil { - log.Error().Err(err).Msg("failed to marshal testcases") - return nil - } - return profileBytes -} - -func BytesToProfile(profileBytes []byte) *Profile { - var profile *Profile - err := json.Unmarshal(profileBytes, &profile) - if err != nil { - log.Error().Err(err).Msg("failed to unmarshal testcases") - } - return profile -} - -// GetTasksChan getsTasks chan -func (b *Boomer) GetTasksChan() chan *task { - switch b.mode { - case DistributedWorkerMode: - return b.workerRunner.tasksChan - default: - return nil - } -} - -func (b *Boomer) GetRebalanceChan() chan bool { - switch b.mode { - case DistributedWorkerMode: - return b.workerRunner.controller.getRebalanceChan() - default: - return nil - } -} - -func (b *Boomer) SetTestCasesPath(paths []string) { - b.testcasePath = paths -} - -func (b *Boomer) GetTestCasesPath() []string { - return b.testcasePath -} - -func (b *Boomer) ParseTestCasesChan() chan bool { - return b.masterRunner.parseTestCasesChan -} - -// GetMasterHost returns master IP -func (b *Boomer) GetMasterHost() string { - return b.masterHost -} - -// GetState gets worker state -func (b *Boomer) GetState() int32 { - switch b.mode { - case DistributedWorkerMode: - return b.workerRunner.getState() - case DistributedMasterMode: - return b.masterRunner.getState() - default: - return b.localRunner.getState() - } -} - -// SetSpawnCount sets spawn count -func (b *Boomer) SetSpawnCount(spawnCount int64) { - switch b.mode { - case DistributedMasterMode: - b.masterRunner.setSpawnCount(spawnCount) - case DistributedWorkerMode: - b.workerRunner.setSpawnCount(spawnCount) - default: - b.localRunner.setSpawnCount(spawnCount) - } -} - -// SetSpawnRate sets spawn rate -func (b *Boomer) SetSpawnRate(spawnRate float64) { - switch b.mode { - case DistributedMasterMode: - b.masterRunner.setSpawnRate(spawnRate) - case DistributedWorkerMode: - b.workerRunner.setSpawnRate(spawnRate) - default: - b.localRunner.setSpawnRate(spawnRate) - } -} - -// SetRunTime sets run time -func (b *Boomer) SetRunTime(runTime int64) { - switch b.mode { - case DistributedMasterMode: - b.masterRunner.setRunTime(runTime) - case DistributedWorkerMode: - b.workerRunner.setRunTime(runTime) - default: - b.localRunner.setRunTime(runTime) - } -} - -// SetExpectWorkers sets expect workers while load testing -func (b *Boomer) SetExpectWorkers(expectWorkers int, expectWorkersMaxWait int) { - b.masterRunner.setExpectWorkers(expectWorkers, expectWorkersMaxWait) -} - -// SetRateLimiter creates rate limiter with the given limit and burst. -func (b *Boomer) SetRateLimiter(maxRPS int64, requestIncreaseRate string) { - var rateLimiter RateLimiter - var err error - if requestIncreaseRate != "-1" { - if maxRPS <= 0 { - maxRPS = math.MaxInt64 - } - log.Warn().Int64("maxRPS", maxRPS).Str("increaseRate", requestIncreaseRate).Msg("set ramp up rate limiter") - rateLimiter, err = NewRampUpRateLimiter(maxRPS, requestIncreaseRate, time.Second) - } else { - if maxRPS > 0 { - log.Warn().Int64("maxRPS", maxRPS).Msg("set stable rate limiter") - rateLimiter = NewStableRateLimiter(maxRPS, time.Second) - } - } - if err != nil { - log.Error().Err(err).Msg("failed to create rate limiter") - return - } - - if rateLimiter != nil { - switch b.mode { - case DistributedWorkerMode: - b.workerRunner.rateLimitEnabled = true - b.workerRunner.rateLimiter = rateLimiter - case StandaloneMode: - b.localRunner.rateLimitEnabled = true - b.localRunner.rateLimiter = rateLimiter - } - } -} - -// SetDisableKeepAlive disable keep-alive for tcp -func (b *Boomer) SetDisableKeepAlive(disableKeepalive bool) { - b.disableKeepalive = disableKeepalive -} - -// SetIgnoreQuit not quit while master quit -func (b *Boomer) SetIgnoreQuit() { - b.workerRunner.ignoreQuit = true -} - -// SetDisableCompression disable compression to prevent the Transport from requesting compression with an "Accept-Encoding: gzip" -func (b *Boomer) SetDisableCompression(disableCompression bool) { - b.disableCompression = disableCompression -} - -func (b *Boomer) GetDisableKeepAlive() bool { - return b.disableKeepalive -} - -func (b *Boomer) GetDisableCompression() bool { - return b.disableCompression -} - -// SetLoopCount set loop count for test. -func (b *Boomer) SetLoopCount(loopCount int64) { - // total loop count for testcase, it will be evenly distributed to each worker - switch b.mode { - case DistributedWorkerMode: - b.workerRunner.loop = &Loop{loopCount: loopCount * b.workerRunner.getSpawnCount()} - case DistributedMasterMode: - b.masterRunner.loop = &Loop{loopCount: loopCount * b.masterRunner.getSpawnCount()} - case StandaloneMode: - b.localRunner.loop = &Loop{loopCount: loopCount * b.localRunner.getSpawnCount()} - } -} - -// AddOutput accepts outputs which implements the boomer.Output interface. -func (b *Boomer) AddOutput(o Output) { - switch b.mode { - case DistributedWorkerMode: - b.workerRunner.addOutput(o) - case DistributedMasterMode: - b.masterRunner.addOutput(o) - case StandaloneMode: - b.localRunner.addOutput(o) - } -} - -// EnableCPUProfile will start cpu profiling after run. -func (b *Boomer) EnableCPUProfile(cpuProfile string, duration time.Duration) { - b.cpuProfile = cpuProfile - b.cpuProfileDuration = duration -} - -// EnableMemoryProfile will start memory profiling after run. -func (b *Boomer) EnableMemoryProfile(memoryProfile string, duration time.Duration) { - b.memoryProfile = memoryProfile - b.memoryProfileDuration = duration -} - -// EnableGracefulQuit catch SIGINT and SIGTERM signals to quit gracefully -func (b *Boomer) EnableGracefulQuit(ctx context.Context) context.Context { - ctx, cancel := context.WithCancel(ctx) - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGTERM, syscall.SIGINT) - go func() { - <-c - b.Quit() - cancel() - }() - return ctx -} - -// Run accepts a slice of Task and connects to the locust master. -func (b *Boomer) Run(tasks ...*Task) { - if b.cpuProfile != "" { - err := startCPUProfile(b.cpuProfile, b.cpuProfileDuration) - if err != nil { - log.Error().Err(err).Msg("failed to start cpu profiling") - } - } - if b.memoryProfile != "" { - err := startMemoryProfile(b.memoryProfile, b.memoryProfileDuration) - if err != nil { - log.Error().Err(err).Msg("failed to start memory profiling") - } - } - - switch b.mode { - case DistributedWorkerMode: - log.Info().Msg("running in worker mode") - b.workerRunner.setTasks(tasks) - b.workerRunner.start() - case StandaloneMode: - log.Info().Msg("running in standalone mode") - b.localRunner.setTasks(tasks) - b.localRunner.start() - default: - log.Error().Err(errors.New("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")) - } -} - -func (b *Boomer) SetTasks(tasks ...*Task) { - switch b.mode { - case DistributedWorkerMode: - log.Info().Msg("set tasks to worker") - b.workerRunner.setTasks(tasks) - case StandaloneMode: - log.Info().Msg("set tasks to standalone") - b.localRunner.setTasks(tasks) - default: - log.Error().Err(errors.New("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")) - } -} - -// RecordTransaction reports a transaction stat. -func (b *Boomer) RecordTransaction(name string, success bool, elapsedTime int64, contentSize int64) { - var runnerStats *requestStats - switch b.mode { - case DistributedWorkerMode: - runnerStats = b.workerRunner.stats - case DistributedMasterMode: - runnerStats = b.masterRunner.stats - case StandaloneMode: - runnerStats = b.localRunner.stats - } - runnerStats.transactionChan <- &transaction{ - name: name, - success: success, - elapsedTime: elapsedTime, - contentSize: contentSize, - } -} - -// RecordSuccess reports a success. -func (b *Boomer) RecordSuccess(requestType, name string, responseTime int64, responseLength int64) { - var runnerStats *requestStats - switch b.mode { - case DistributedWorkerMode: - runnerStats = b.workerRunner.stats - case DistributedMasterMode: - runnerStats = b.masterRunner.stats - case StandaloneMode: - runnerStats = b.localRunner.stats - } - runnerStats.requestSuccessChan <- &requestSuccess{ - requestType: requestType, - name: name, - responseTime: responseTime, - responseLength: responseLength, - } -} - -// RecordFailure reports a failure. -func (b *Boomer) RecordFailure(requestType, name string, responseTime int64, exception string) { - var runnerStats *requestStats - switch b.mode { - case DistributedWorkerMode: - runnerStats = b.workerRunner.stats - case DistributedMasterMode: - runnerStats = b.masterRunner.stats - case StandaloneMode: - runnerStats = b.localRunner.stats - } - runnerStats.requestFailureChan <- &requestFailure{ - requestType: requestType, - name: name, - responseTime: responseTime, - errMsg: exception, - } -} - -// Start starts to run -func (b *Boomer) Start(Args *Profile) error { - if b.masterRunner.isStarting() { - return errors.New("already started") - } - if b.masterRunner.isStopping() { - return errors.New("Please wait for all workers to finish") - } - if int(Args.SpawnCount) < b.masterRunner.server.getAvailableClientsLength() { - return errors.New("spawn count should be greater than available worker count") - } - b.SetSpawnCount(Args.SpawnCount) - b.SetSpawnRate(Args.SpawnRate) - b.SetRunTime(Args.RunTime) - b.SetProfile(Args) - err := b.masterRunner.start() - return err -} - -// ReBalance starts to rebalance load test -func (b *Boomer) ReBalance(Args *Profile) error { - if !b.masterRunner.isStarting() { - return errors.New("no start") - } - if int(Args.SpawnCount) < b.masterRunner.server.getAvailableClientsLength() { - return errors.New("spawn count should be greater than available worker count") - } - b.SetSpawnCount(Args.SpawnCount) - b.SetSpawnRate(Args.SpawnRate) - b.SetRunTime(Args.RunTime) - b.SetProfile(Args) - err := b.masterRunner.rebalance() - if err != nil { - log.Error().Err(err).Msg("failed to rebalance") - } - return err -} - -// Stop stops to load test -func (b *Boomer) Stop() error { - return b.masterRunner.stop() -} - -// GetWorkersInfo gets workers information -func (b *Boomer) GetWorkersInfo() []WorkerNode { - return b.masterRunner.server.getAllWorkers() -} - -// GetMasterInfo gets master information -func (b *Boomer) GetMasterInfo() map[string]interface{} { - masterInfo := make(map[string]interface{}) - masterInfo["state"] = b.masterRunner.getState() - masterInfo["workers"] = b.masterRunner.server.getAvailableClientsLength() - masterInfo["target_users"] = b.masterRunner.getSpawnCount() - masterInfo["current_users"] = b.masterRunner.server.getCurrentUsers() - return masterInfo -} - -func (b *Boomer) GetCloseChan() chan bool { - switch b.mode { - case DistributedWorkerMode: - return b.workerRunner.closeChan - case DistributedMasterMode: - return b.masterRunner.closeChan - default: - return b.localRunner.closeChan - } -} - -// Quit will send a quit message to the master. -func (b *Boomer) Quit() { - switch b.mode { - case DistributedWorkerMode: - b.workerRunner.stop() - b.workerRunner.close() - case DistributedMasterMode: - b.masterRunner.close() - case StandaloneMode: - b.localRunner.stop() - } -} - -func (b *Boomer) GetSpawnDoneChan() chan struct{} { - switch b.mode { - case DistributedWorkerMode: - return b.workerRunner.controller.getSpawnDone() - case DistributedMasterMode: - return b.masterRunner.controller.getSpawnDone() - default: - return b.localRunner.controller.getSpawnDone() - } -} - -func (b *Boomer) GetSpawnCount() int { - switch b.mode { - case DistributedWorkerMode: - return int(b.workerRunner.getSpawnCount()) - case DistributedMasterMode: - return int(b.masterRunner.getSpawnCount()) - default: - return int(b.localRunner.getSpawnCount()) - } -} - -func (b *Boomer) ResetStartTime() { - switch b.mode { - case DistributedWorkerMode: - b.workerRunner.stats.total.resetStartTime() - case DistributedMasterMode: - b.masterRunner.stats.total.resetStartTime() - default: - b.localRunner.stats.total.resetStartTime() - } -} diff --git a/hrp/pkg/boomer/boomer_test.go b/hrp/pkg/boomer/boomer_test.go deleted file mode 100644 index 7f113f87..00000000 --- a/hrp/pkg/boomer/boomer_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package boomer - -import ( - "math" - "os" - "runtime" - "sync/atomic" - "testing" - "time" -) - -func TestNewStandaloneBoomer(t *testing.T) { - b := NewStandaloneBoomer(100, 10) - - if b.localRunner.spawnCount != 100 { - t.Error("spawnCount should be 100") - } - - if b.localRunner.spawnRate != 10 { - t.Error("spawnRate should be 10") - } -} - -func TestSetRateLimiter(t *testing.T) { - b := NewStandaloneBoomer(100, 10) - b.SetRateLimiter(10, "10/1s") - - if b.localRunner.rateLimiter == nil { - t.Error("b.rateLimiter should not be nil") - } -} - -func TestAddOutput(t *testing.T) { - b := NewStandaloneBoomer(100, 10) - b.AddOutput(NewConsoleOutput()) - b.AddOutput(NewConsoleOutput()) - - if len(b.localRunner.outputs) != 2 { - t.Error("length of outputs should be 2") - } -} - -func TestEnableCPUProfile(t *testing.T) { - b := NewStandaloneBoomer(100, 10) - b.EnableCPUProfile("cpu.prof", time.Second) - - if b.cpuProfile != "cpu.prof" { - t.Error("cpuProfile should be cpu.prof") - } - - if b.cpuProfileDuration != time.Second { - t.Error("cpuProfileDuration should 1 second") - } -} - -func TestEnableMemoryProfile(t *testing.T) { - b := NewStandaloneBoomer(100, 10) - b.EnableMemoryProfile("mem.prof", time.Second) - - if b.memoryProfile != "mem.prof" { - t.Error("memoryProfile should be mem.prof") - } - - if b.memoryProfileDuration != time.Second { - t.Error("memoryProfileDuration should 1 second") - } -} - -func TestStandaloneRun(t *testing.T) { - b := NewStandaloneBoomer(10, 10) - b.EnableCPUProfile("cpu.pprof", 2*time.Second) - b.EnableMemoryProfile("mem.pprof", 2*time.Second) - - count := int64(0) - taskA := &Task{ - Name: "increaseCount", - Fn: func() { - atomic.AddInt64(&count, 1) - runtime.Goexit() - }, - } - go b.Run(taskA) - - time.Sleep(5 * time.Second) - - b.Quit() - - if atomic.LoadInt64(&count) != 10 { - t.Error("count is", count, "expected: 10") - } - - if _, err := os.Stat("cpu.pprof"); os.IsNotExist(err) { - t.Error("File cpu.pprof is not generated") - } else { - os.Remove("cpu.pprof") - } - - if _, err := os.Stat("mem.pprof"); os.IsNotExist(err) { - t.Error("File mem.pprof is not generated") - } else { - os.Remove("mem.pprof") - } -} - -func TestCreateRatelimiter(t *testing.T) { - b := NewStandaloneBoomer(10, 10) - b.SetRateLimiter(100, "-1") - - if stableRateLimiter, ok := b.localRunner.rateLimiter.(*StableRateLimiter); !ok { - t.Error("Expected stableRateLimiter") - } else { - if stableRateLimiter.threshold != 100 { - t.Error("threshold should be equals to math.MaxInt64, was", stableRateLimiter.threshold) - } - } - - b.SetRateLimiter(0, "1") - if rampUpRateLimiter, ok := b.localRunner.rateLimiter.(*RampUpRateLimiter); !ok { - t.Error("Expected rampUpRateLimiter") - } else { - if rampUpRateLimiter.maxThreshold != math.MaxInt64 { - t.Error("maxThreshold should be equals to math.MaxInt64, was", rampUpRateLimiter.maxThreshold) - } - if rampUpRateLimiter.rampUpRate != "1" { - t.Error("rampUpRate should be equals to \"1\", was", rampUpRateLimiter.rampUpRate) - } - } - - b.SetRateLimiter(10, "2/2s") - if rampUpRateLimiter, ok := b.localRunner.rateLimiter.(*RampUpRateLimiter); !ok { - t.Error("Expected rampUpRateLimiter") - } else { - if rampUpRateLimiter.maxThreshold != 10 { - t.Error("maxThreshold should be equals to 10, was", rampUpRateLimiter.maxThreshold) - } - if rampUpRateLimiter.rampUpRate != "2/2s" { - t.Error("rampUpRate should be equals to \"2/2s\", was", rampUpRateLimiter.rampUpRate) - } - if rampUpRateLimiter.rampUpStep != 2 { - t.Error("rampUpStep should be equals to 2, was", rampUpRateLimiter.rampUpStep) - } - if rampUpRateLimiter.rampUpPeroid != 2*time.Second { - t.Error("rampUpPeroid should be equals to 2 seconds, was", rampUpRateLimiter.rampUpPeroid) - } - } -} diff --git a/hrp/pkg/boomer/client_grpc.go b/hrp/pkg/boomer/client_grpc.go deleted file mode 100644 index 67484003..00000000 --- a/hrp/pkg/boomer/client_grpc.go +++ /dev/null @@ -1,336 +0,0 @@ -package boomer - -import ( - "context" - "fmt" - "runtime" - "sync" - "sync/atomic" - "time" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" - "golang.org/x/oauth2" - "google.golang.org/grpc" - "google.golang.org/grpc/backoff" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/oauth" - "google.golang.org/grpc/metadata" - - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/data" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/grpc/messager" -) - -type grpcClient struct { - messager.MessageClient - masterHost string - masterPort int - identity string // nodeID - - config *grpcClientConfig - - fromMaster chan *genericMessage - toMaster chan *genericMessage - disconnectedChan chan bool - shutdownChan chan bool - - failCount int32 -} - -type grpcClientConfig struct { - // ctx is used for the lifetime of the stream that may need to be canceled - // on client shutdown. - ctx context.Context - ctxCancel context.CancelFunc - conn *grpc.ClientConn - biStream messager.Message_BidirectionalStreamingMessageClient - - mutex sync.RWMutex -} - -const token = "httprunner-secret-token" - -// unaryInterceptor is an example unary interceptor. -func unaryInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - var credsConfigured bool - for _, o := range opts { - _, ok := o.(grpc.PerRPCCredsCallOption) - if ok { - credsConfigured = true - break - } - } - if !credsConfigured { - opts = append(opts, grpc.PerRPCCredentials(oauth.NewOauthAccess(&oauth2.Token{ - AccessToken: token, - }))) - } - start := time.Now() - err := invoker(ctx, method, req, reply, cc, opts...) - end := time.Now() - logger("RPC: %s, start time: %s, end time: %s, err: %v", method, start.Format("Basic"), end.Format(time.RFC3339), err) - return err -} - -// wrappedStream wraps around the embedded grpc.ClientStream, and intercepts the RecvMsg and -// SendMsg method call. -type wrappedStream struct { - grpc.ClientStream -} - -func (w *wrappedStream) RecvMsg(m interface{}) error { - logger("Receive a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339)) - return w.ClientStream.RecvMsg(m) -} - -func (w *wrappedStream) SendMsg(m interface{}) error { - logger("Send a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339)) - return w.ClientStream.SendMsg(m) -} - -func newWrappedStream(s grpc.ClientStream) grpc.ClientStream { - return &wrappedStream{s} -} - -func extractToken(ctx context.Context) (tkn string, ok bool) { - md, ok := metadata.FromIncomingContext(ctx) - if !ok || len(md[token]) == 0 { - return "", false - } - - return md[token][0], true -} - -// streamInterceptor is an example stream interceptor. -func streamInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - var credsConfigured bool - for _, o := range opts { - _, ok := o.(*grpc.PerRPCCredsCallOption) - if ok { - credsConfigured = true - break - } - } - if !credsConfigured { - opts = append(opts, grpc.PerRPCCredentials(oauth.NewOauthAccess(&oauth2.Token{ - AccessToken: token, - }))) - } - s, err := streamer(ctx, desc, cc, method, opts...) - if err != nil { - return nil, err - } - return newWrappedStream(s), nil -} - -func (c *grpcClientConfig) getBiStreamClient() messager.Message_BidirectionalStreamingMessageClient { - c.mutex.RLock() - defer c.mutex.RUnlock() - return c.biStream -} - -func (c *grpcClientConfig) setBiStreamClient(s messager.Message_BidirectionalStreamingMessageClient) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.biStream = s -} - -func newClient(masterHost string, masterPort int, identity string) (client *grpcClient) { - log.Info().Msg("Boomer is built with grpc support.") - // Initiate the stream with a context that supports cancellation. - ctx, cancel := context.WithCancel(context.Background()) - client = &grpcClient{ - masterHost: masterHost, - masterPort: masterPort, - identity: identity, - fromMaster: make(chan *genericMessage, 100), - toMaster: make(chan *genericMessage, 100), - disconnectedChan: make(chan bool), - shutdownChan: make(chan bool), - config: &grpcClientConfig{ - ctx: ctx, - ctxCancel: cancel, - mutex: sync.RWMutex{}, - }, - } - return client -} - -func (c *grpcClient) start() (err error) { - addr := fmt.Sprintf("%v:%v", c.masterHost, c.masterPort) - // Create tls based credential. - creds, err := credentials.NewClientTLSFromFile(data.Path("x509/ca_cert.pem"), "www.httprunner.com") - if err != nil { - log.Fatal().Msg(fmt.Sprintf("failed to load credentials: %v", err)) - } - opts := []grpc.DialOption{ - // oauth.NewOauthAccess requires the configuration of transport - // credentials. - grpc.WithTransportCredentials(creds), - grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(32 * 10e9)), - grpc.WithUnaryInterceptor(unaryInterceptor), - grpc.WithStreamInterceptor(streamInterceptor), - grpc.WithConnectParams(grpc.ConnectParams{ - Backoff: backoff.Config{ - BaseDelay: 1 * time.Second, - Multiplier: 1.2, - MaxDelay: 3 * time.Second, - }, - MinConnectTimeout: 3 * time.Second, - }), - } - c.config.conn, err = grpc.Dial(addr, opts...) - if err != nil { - log.Error().Err(err).Msg("failed to connect") - return err - } - c.MessageClient = messager.NewMessageClient(c.config.conn) - return nil -} - -func (c *grpcClient) register(ctx context.Context) error { - ctx, cancel := context.WithTimeout(ctx, time.Second) - defer cancel() - res, err := c.Register(ctx, &messager.RegisterRequest{NodeID: c.identity, Os: runtime.GOOS, Arch: runtime.GOARCH}) - if err != nil { - return err - } - if res.Code != "0" { - return errors.New(res.Message) - } - return nil -} - -func (c *grpcClient) signOut(ctx context.Context) error { - ctx, cancel := context.WithTimeout(ctx, time.Second) - defer cancel() - - res, err := c.SignOut(ctx, &messager.SignOutRequest{NodeID: c.identity}) - if err != nil { - return err - } - if res.Code != "0" { - return errors.New(res.Message) - } - return nil -} - -func (c *grpcClient) newBiStreamClient() (err error) { - md := metadata.New(map[string]string{token: c.identity}) - ctx := metadata.NewOutgoingContext(c.config.ctx, md) - biStream, err := c.BidirectionalStreamingMessage(ctx) - if err != nil { - return err - } - // reset failCount - atomic.StoreInt32(&c.failCount, 0) - // set bidirectional stream client - c.config.setBiStreamClient(biStream) - println("successful to establish bidirectional stream with master, press Ctrl+c to quit.") - return nil -} - -func (c *grpcClient) recvChannel() chan *genericMessage { - return c.fromMaster -} - -func (c *grpcClient) recv() { - for { - select { - case <-c.shutdownChan: - return - default: - if c.config.getBiStreamClient() == nil { - time.Sleep(1 * time.Second) - continue - } - msg, err := c.config.getBiStreamClient().Recv() - if err != nil { - time.Sleep(1 * time.Second) - // log.Error().Err(err).Msg("failed to get message") - continue - } - if msg == nil { - continue - } - - if msg.NodeID != c.identity { - log.Info(). - Str("nodeID", msg.NodeID). - Str("type", msg.Type). - Interface("data", msg.Data). - Msg(fmt.Sprintf("not for me(%s)", c.identity)) - continue - } - - c.fromMaster <- &genericMessage{ - Type: msg.Type, - Profile: msg.Profile, - Data: msg.Data, - NodeID: msg.NodeID, - Tasks: msg.Tasks, - } - - log.Info(). - Str("nodeID", msg.NodeID). - Str("type", msg.Type). - Interface("data", msg.Data). - Interface("tasks", msg.Tasks). - Msg("receive data from master") - } - } -} - -func (c *grpcClient) sendChannel() chan *genericMessage { - return c.toMaster -} - -func (c *grpcClient) send() { - for { - select { - case <-c.shutdownChan: - return - case msg := <-c.toMaster: - c.sendMessage(msg) - - // We may send genericMessage to master. - switch msg.Type { - case "quit": - c.disconnectedChan <- true - } - } - } -} - -func (c *grpcClient) sendMessage(msg *genericMessage) { - log.Info(). - Str("nodeID", msg.NodeID). - Str("type", msg.Type). - Interface("data", msg.Data). - Msg("send data to server") - if c.config.getBiStreamClient() == nil { - atomic.AddInt32(&c.failCount, 1) - return - } - err := c.config.getBiStreamClient().Send(&messager.StreamRequest{Type: msg.Type, Data: msg.Data, NodeID: msg.NodeID}) - if err == nil { - atomic.StoreInt32(&c.failCount, 0) - return - } - // log.Error().Err(err).Interface("genericMessage", *msg).Msg("failed to send message") - if msg.Type == "heartbeat" { - atomic.AddInt32(&c.failCount, 1) - } -} - -func (c *grpcClient) disconnectedChannel() chan bool { - return c.disconnectedChan -} - -func (c *grpcClient) close() { - close(c.shutdownChan) - c.config.ctxCancel() - if c.config.conn != nil { - c.config.conn.Close() - } -} diff --git a/hrp/pkg/boomer/client_grpc_test.go b/hrp/pkg/boomer/client_grpc_test.go deleted file mode 100644 index 853e847e..00000000 --- a/hrp/pkg/boomer/client_grpc_test.go +++ /dev/null @@ -1 +0,0 @@ -package boomer diff --git a/hrp/pkg/boomer/data/data.go b/hrp/pkg/boomer/data/data.go deleted file mode 100644 index bdb1f48c..00000000 --- a/hrp/pkg/boomer/data/data.go +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package data - -import ( - "embed" - "os" - "path/filepath" - - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" -) - -// hrpPath is .hrp directory under the user directory. -var hrpPath string - -//go:embed x509/* -var x509Dir embed.FS - -func init() { - home, err := os.UserHomeDir() - if err != nil { - return - } - hrpPath = filepath.Join(home, ".hrp") - _ = builtin.EnsureFolderExists(filepath.Join(hrpPath, "x509")) -} - -// Path returns the absolute path the given relative file or directory path -func Path(rel string) (destPath string) { - destPath = rel - if !filepath.IsAbs(rel) { - destPath = filepath.Join(hrpPath, rel) - } - if !builtin.IsFilePathExists(destPath) { - content, err := x509Dir.ReadFile(rel) - if err != nil { - return - } - - err = os.WriteFile(destPath, content, 0o644) - if err != nil { - return - } - } - return -} diff --git a/hrp/pkg/boomer/data/x509/README.md b/hrp/pkg/boomer/data/x509/README.md deleted file mode 100644 index 3b9a05da..00000000 --- a/hrp/pkg/boomer/data/x509/README.md +++ /dev/null @@ -1,6 +0,0 @@ -This directory contains x509 certificates and associated private keys used in -examples. - -How were these test certs/keys generated ? ------------------------------------------- -Run `./create.sh` diff --git a/hrp/pkg/boomer/data/x509/ca_cert.pem b/hrp/pkg/boomer/data/x509/ca_cert.pem deleted file mode 100644 index 14db0ba7..00000000 --- a/hrp/pkg/boomer/data/x509/ca_cert.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- diff --git a/hrp/pkg/boomer/data/x509/ca_key.pem b/hrp/pkg/boomer/data/x509/ca_key.pem deleted file mode 100644 index c1320a1f..00000000 --- a/hrp/pkg/boomer/data/x509/ca_key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -8xnynnp57i3BHHHbjY4R02Mqsfi1nNoN ------END PRIVATE KEY----- diff --git a/hrp/pkg/boomer/data/x509/client_ca_cert.pem b/hrp/pkg/boomer/data/x509/client_ca_cert.pem deleted file mode 100644 index 52ae25ec..00000000 --- a/hrp/pkg/boomer/data/x509/client_ca_cert.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- diff --git a/hrp/pkg/boomer/data/x509/client_ca_key.pem b/hrp/pkg/boomer/data/x509/client_ca_key.pem deleted file mode 100644 index b546d6e2..00000000 --- a/hrp/pkg/boomer/data/x509/client_ca_key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -+3KzjPLML31OD8TN22FUzsYcdw2prEU= ------END PRIVATE KEY----- diff --git a/hrp/pkg/boomer/data/x509/client_cert.pem b/hrp/pkg/boomer/data/x509/client_cert.pem deleted file mode 100644 index c9dbafe9..00000000 --- a/hrp/pkg/boomer/data/x509/client_cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFcTCCA1mgAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx -CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV -BAMMDnRlc3QtY2xpZW50X2NhMB4XDTIyMDcxMDA0MzAxNVoXDTMyMDcwNzA0MzAx -NVowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL -BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3QtY2xpZW50MTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAK36523v5SEM+J8ReNt3USwylERoUMqygoQRTIy7 -ipzfO2dmo5OANFsJtPb3CH+YB6kS9llAioLa9UNrD6SBlR23No/QJeXBiXgpUXAE -DCLhQ/aj0fEy8AEnW+a6mM5jmsEHOy/O3q/KF1JdjNA1T7HuBS6cIvp5+7rF1rG9 -tzJLLrXwUZLKlMjdCDuLxp/qtYUoH81CIuveWAODH3oad559HgD6UBgDRntdT902 -IUnTejCAOY9Q0yTlcMMbz+FEMZ43Xq4E89YQ7Mel+xkb0lL7H6mNabvfZTX+5qm9 -RDtxrNvLH+hZ+OPOp2qrfyJBaj/yP+4TTN4pC4y5Vqkq7sZ1fjfx9gZTsQLAvmr6 -/c/Z59IlsAIvttbam7FFNrwVlWsD5uRP2DZyKXTjRRCA8NnBo9fltD1FbKKevcqu -PilMiyg8+dJnhKxOeMlw1WSx0h8FFU+jf4MFFX+qFsJB7Ecss1bWpnoYsaeKGMG7 -mcOx5weglRlVccDQollZBXoIM/pDKJNrAbA8otKXbGGl1LJY20HZLNYPIRRlH2pe -YoLyhUi1AKFMecHxcGOIxlHVZ0gfEoWcChYvlWi6M/09c2Qtqq/QfKhD7DAXmMDS -xYFskyAAYSxgX2Q/5Y6mP+qRzDxT0Qm5JyN+UV0laqQ1KBA11+BF8RKriMGYSXy4 -afDJAgMBAAGjVzBVMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNv1CHU7dlRoE4Lh -/elJzmaSFpU5MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSUBAf8EDDAKBggrBgEFBQcD -AjANBgkqhkiG9w0BAQsFAAOCAgEAoF0Jc770+dMNNiDyKsGOPgUJBsYMTyGqPmpd -7Nu7wmI+PBlgDkTvVZjU3EO/Y5Ez6fum5gCtf7OKPIYLfV95WBxgkkEvBEYaX4To -eL9nr9jP9AQ9sZocPTSCrlVrIeOT3tV683BY+N8sfHW6xIeI9tqTXTExCKmwuKyZ -+qyokn35Kkydyn47J4bclPD56UWctQinO2cXm2RVHkJlmQSoFREdb0S3xiFt8aAW -olB2xWMCwXb7LDyi5M0HCvz3lGErCTnpL9GBPjsWCSZOK55D/BSxL4NRSBqzsv4N -25SQOP2NgIqabRsYqYhTCRWK0n1h3IBAVh6fVQ2CCStd4gkuDUepTfM+R7mcYR9g -u2hn4kn+1i8y+Uj0z6yN48/i9Cnz3Sq/e8Z48Rbjut5Rx32ldFvHIkdtFjjkgv47 -LbVKaYH4uqQF2xs3tAPuqq/QXNOn8Ie9yHv0MeJiPymIPAk6GBrUOA/Br4kof15v -uEbxeR/nnrzm+eyWMn4dsE0n7GA6wm2gMGENK4E8WK0sYujIAPtG8LHfShEv5f/j -77+3tAcigec39bau4yTkXBV8op1iMPBtEejLD0B5RKZig17Bfdw5v2TP+yGbzD5d -PwhAxn4aVK8zXFdYmwNfXNXBpLaEILxYFpeExaA9Gr5Mn/h+vD987GTW9F4fBhht -MtkfvRA= ------END CERTIFICATE----- diff --git a/hrp/pkg/boomer/data/x509/client_key.pem b/hrp/pkg/boomer/data/x509/client_key.pem deleted file mode 100644 index 51fdcde0..00000000 --- a/hrp/pkg/boomer/data/x509/client_key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/hrp/pkg/boomer/data/x509/create.sh b/hrp/pkg/boomer/data/x509/create.sh deleted file mode 100755 index 2b5aa5cf..00000000 --- a/hrp/pkg/boomer/data/x509/create.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -# Create the server CA certs. -openssl req -x509 \ - -newkey rsa:4096 \ - -nodes \ - -days 3650 \ - -keyout ca_key.pem \ - -out ca_cert.pem \ - -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-server_ca/ \ - -config ./openssl.cnf \ - -extensions test_ca \ - -sha256 - -# Create the client CA certs. -openssl req -x509 \ - -newkey rsa:4096 \ - -nodes \ - -days 3650 \ - -keyout client_ca_key.pem \ - -out client_ca_cert.pem \ - -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-client_ca/ \ - -config ./openssl.cnf \ - -extensions test_ca \ - -sha256 - -# Generate a server cert. -openssl genrsa -out server_key.pem 4096 -openssl req -new \ - -key server_key.pem \ - -days 3650 \ - -out server_csr.pem \ - -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-server1/ \ - -config ./openssl.cnf \ - -reqexts test_server -openssl x509 -req \ - -in server_csr.pem \ - -CAkey ca_key.pem \ - -CA ca_cert.pem \ - -days 3650 \ - -set_serial 1000 \ - -out server_cert.pem \ - -extfile ./openssl.cnf \ - -extensions test_server \ - -sha256 -openssl verify -verbose -CAfile ca_cert.pem server_cert.pem - -# Generate a client cert. -openssl genrsa -out client_key.pem 4096 -openssl req -new \ - -key client_key.pem \ - -days 3650 \ - -out client_csr.pem \ - -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-client1/ \ - -config ./openssl.cnf \ - -reqexts test_client -openssl x509 -req \ - -in client_csr.pem \ - -CAkey client_ca_key.pem \ - -CA client_ca_cert.pem \ - -days 3650 \ - -set_serial 1000 \ - -out client_cert.pem \ - -extfile ./openssl.cnf \ - -extensions test_client \ - -sha256 -openssl verify -verbose -CAfile client_ca_cert.pem client_cert.pem - -rm *_csr.pem diff --git a/hrp/pkg/boomer/data/x509/openssl.cnf b/hrp/pkg/boomer/data/x509/openssl.cnf deleted file mode 100644 index cdafc663..00000000 --- a/hrp/pkg/boomer/data/x509/openssl.cnf +++ /dev/null @@ -1,28 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -attributes = req_attributes - -[req_distinguished_name] - -[req_attributes] - -[test_ca] -basicConstraints = critical,CA:TRUE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer:always -keyUsage = critical,keyCertSign - -[test_server] -basicConstraints = critical,CA:FALSE -subjectKeyIdentifier = hash -keyUsage = critical,digitalSignature,keyEncipherment,keyAgreement -subjectAltName = @server_alt_names - -[server_alt_names] -DNS.1 = *.httprunner.com - -[test_client] -basicConstraints = critical,CA:FALSE -subjectKeyIdentifier = hash -keyUsage = critical,nonRepudiation,digitalSignature,keyEncipherment -extendedKeyUsage = critical,clientAuth diff --git a/hrp/pkg/boomer/data/x509/server_cert.pem b/hrp/pkg/boomer/data/x509/server_cert.pem deleted file mode 100644 index 8f4661a0..00000000 --- a/hrp/pkg/boomer/data/x509/server_cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFdjCCA16gAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCVVMx -CzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFzAVBgNV -BAMMDnRlc3Qtc2VydmVyX2NhMB4XDTIyMDcxMDA0MzAxNFoXDTMyMDcwNzA0MzAx -NFowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTAL -BgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3Qtc2VydmVyMTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAL0HTaTaYQ1GbvZ/Py3NJf3WSOzXdm/qh9Fv7hAs -8FGPEEDCRhrvFMjWqAwp3EiQkRavLgTv4t1hkga9y/hc7t/q9ATFm8SC3Dtdkg2X -0YdxsyotPaWgUSmsIJ0uwCIMkU5oGE1J2fopdBxG87T+QGUo1r4QxDQGQ2H9CMsD -217Ca+PdrdldctNs/D2AVkXTew1Bd/nNaOXh3vc14/4b86Y7A2HOFFyRi3QaemJJ -ksnH0CmhydRob5rAZQRClftzjri9gaUfJW5LSUYBXn3Yx1gam6lM5LcPlgWLmXs9 -wthfksY6YlpCa1NtdnNbZIY+6cCHN6ytSPj/1BY8+C954cySSuNVSsAAvm8C80Zz -hnNaivhdouvmWTZM8febnrrt6qo0SEtnn+RkzUznOjVVxyPffgjI8s4gNc3DAIbf -oDwrAgxNF9nXAoeYTVOUxeGcjeG8fIKcfC7pxfI6/ejMiUU7LkL5rEIbfT2bF6EW -ntGyrxYRNdw+VX2MxNNvPKHUUu90JTCxzjaUCSnR4lhatcQPKeYVnn5I+jv6kMm5 -FAkjVwk4U/u7W1DtCedaN9nUJNRWwptHqX2VXcnM0k9tA5yBtBM55yf0zYHz/fOz -RJ/bqHzbs5+il07u1uedMUJ9X9pp85Pm0PFD1zbv8MwZetTJigA4CdU4XU8K56Nz -Avc1AgMBAAGjXDBaMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFI0rfKZ3rjLJZ3R4 -tv5NeYgJyiaqMA4GA1UdDwEB/wQEAwIDqDAbBgNVHREEFDASghAqLmh0dHBydW5u -ZXIuY29tMA0GCSqGSIb3DQEBCwUAA4ICAQCYbWsz11jUxABZDkQDNqGGpdAEJuaD -gAe3Ko28ntT+pjEdInD/YrfEjGI3KQhT00yMVkiWXiK8bBynZB3TpDUfG4OTBhAV -PZy/jQ08wOfmgFQco3asxQovimmKXVwbeJBOlZBfZoseB3h4zz7PcfLI9Xr8dz34 -Pbilg+XOZywoxdHWd1To13ycKi9DPh81cRWu7QACS92wGGsX/eYVW7YKFmjcnj0I -2+WJl7nHD7h+Qyy6QiHmHa6/ZKAx2vkf2ALAHr4zKvIf+LLlQVTKGxtkyRMusiP+ -sZuDq7RN5oYE5G1P5tF6Xb6AUGFrazaiC3kI0K3njs0xifjxiM+7KyfXQHOWV/a6 -NNk9CX9twaKhq8Ay5jjILSUoXWgyl1OXOyIHIpWmsJMyGrQCapS5BZHGwc/K/6yW -TETmn6frJUh8VHJ+gjLvoUVMQvkJbV5IecMQaIfHBegRobi9TDkmjGC1v6+rpfjc -tVhQ7rUQgYtkuoOfRjwvCvY0UQ3hf73u/FCG/+Lw1b/Wcp8PMU+6vpZqlAaaFGVr -WHdrPHC0B0Sc3Pr6dmJp70KVb4gx45icRaJnPLR7sr5CBkorZs9NKXUzNnf9oZWF -Nfm5/isLCqLfwA+VTk78vyWqRycdDJ0lswxZt5pvwI3gXitOhlE6zXtsA883TwZ9 -TxGOtJdjo0IEAQ== ------END CERTIFICATE----- diff --git a/hrp/pkg/boomer/data/x509/server_key.pem b/hrp/pkg/boomer/data/x509/server_key.pem deleted file mode 100644 index aa1850a7..00000000 --- a/hrp/pkg/boomer/data/x509/server_key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/hrp/pkg/boomer/grpc/messager/messager.pb.go b/hrp/pkg/boomer/grpc/messager/messager.pb.go deleted file mode 100644 index 3ad177c5..00000000 --- a/hrp/pkg/boomer/grpc/messager/messager.pb.go +++ /dev/null @@ -1,589 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.4 -// source: grpc/proto/messager.proto - -package messager - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type StreamRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - NodeID string `protobuf:"bytes,2,opt,name=nodeID,proto3" json:"nodeID,omitempty"` - Data map[string][]byte `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *StreamRequest) Reset() { - *x = StreamRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *StreamRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StreamRequest) ProtoMessage() {} - -func (x *StreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead. -func (*StreamRequest) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{0} -} - -func (x *StreamRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *StreamRequest) GetNodeID() string { - if x != nil { - return x.NodeID - } - return "" -} - -func (x *StreamRequest) GetData() map[string][]byte { - if x != nil { - return x.Data - } - return nil -} - -type StreamResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - NodeID string `protobuf:"bytes,2,opt,name=nodeID,proto3" json:"nodeID,omitempty"` - Profile []byte `protobuf:"bytes,3,opt,name=profile,proto3" json:"profile,omitempty"` - Tasks []byte `protobuf:"bytes,4,opt,name=tasks,proto3" json:"tasks,omitempty"` - Data map[string][]byte `protobuf:"bytes,5,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *StreamResponse) Reset() { - *x = StreamResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *StreamResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StreamResponse) ProtoMessage() {} - -func (x *StreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead. -func (*StreamResponse) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{1} -} - -func (x *StreamResponse) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *StreamResponse) GetNodeID() string { - if x != nil { - return x.NodeID - } - return "" -} - -func (x *StreamResponse) GetProfile() []byte { - if x != nil { - return x.Profile - } - return nil -} - -func (x *StreamResponse) GetTasks() []byte { - if x != nil { - return x.Tasks - } - return nil -} - -func (x *StreamResponse) GetData() map[string][]byte { - if x != nil { - return x.Data - } - return nil -} - -type RegisterRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - NodeID string `protobuf:"bytes,1,opt,name=nodeID,proto3" json:"nodeID,omitempty"` - Os string `protobuf:"bytes,2,opt,name=os,proto3" json:"os,omitempty"` - Arch string `protobuf:"bytes,3,opt,name=arch,proto3" json:"arch,omitempty"` -} - -func (x *RegisterRequest) Reset() { - *x = RegisterRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RegisterRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RegisterRequest) ProtoMessage() {} - -func (x *RegisterRequest) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. -func (*RegisterRequest) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{2} -} - -func (x *RegisterRequest) GetNodeID() string { - if x != nil { - return x.NodeID - } - return "" -} - -func (x *RegisterRequest) GetOs() string { - if x != nil { - return x.Os - } - return "" -} - -func (x *RegisterRequest) GetArch() string { - if x != nil { - return x.Arch - } - return "" -} - -type RegisterResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *RegisterResponse) Reset() { - *x = RegisterResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RegisterResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RegisterResponse) ProtoMessage() {} - -func (x *RegisterResponse) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. -func (*RegisterResponse) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{3} -} - -func (x *RegisterResponse) GetCode() string { - if x != nil { - return x.Code - } - return "" -} - -func (x *RegisterResponse) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -type SignOutRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - NodeID string `protobuf:"bytes,1,opt,name=nodeID,proto3" json:"nodeID,omitempty"` -} - -func (x *SignOutRequest) Reset() { - *x = SignOutRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SignOutRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SignOutRequest) ProtoMessage() {} - -func (x *SignOutRequest) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SignOutRequest.ProtoReflect.Descriptor instead. -func (*SignOutRequest) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{4} -} - -func (x *SignOutRequest) GetNodeID() string { - if x != nil { - return x.NodeID - } - return "" -} - -type SignOutResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *SignOutResponse) Reset() { - *x = SignOutResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_grpc_proto_messager_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SignOutResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SignOutResponse) ProtoMessage() {} - -func (x *SignOutResponse) ProtoReflect() protoreflect.Message { - mi := &file_grpc_proto_messager_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SignOutResponse.ProtoReflect.Descriptor instead. -func (*SignOutResponse) Descriptor() ([]byte, []int) { - return file_grpc_proto_messager_proto_rawDescGZIP(), []int{5} -} - -func (x *SignOutResponse) GetCode() string { - if x != nil { - return x.Code - } - return "" -} - -func (x *SignOutResponse) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -var File_grpc_proto_messager_proto protoreflect.FileDescriptor - -var file_grpc_proto_messager_proto_rawDesc = []byte{ - 0x0a, 0x19, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, - 0x64, 0x65, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, - 0x49, 0x44, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0xdc, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x64, 0x65, - 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, - 0x73, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, - 0x12, 0x35, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x4d, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x6f, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, - 0x72, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x22, - 0x40, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x28, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x22, 0x3f, 0x0a, 0x0f, 0x53, - 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, - 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xe4, 0x01, 0x0a, - 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x07, 0x53, - 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1d, 0x42, - 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, - 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_grpc_proto_messager_proto_rawDescOnce sync.Once - file_grpc_proto_messager_proto_rawDescData = file_grpc_proto_messager_proto_rawDesc -) - -func file_grpc_proto_messager_proto_rawDescGZIP() []byte { - file_grpc_proto_messager_proto_rawDescOnce.Do(func() { - file_grpc_proto_messager_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_proto_messager_proto_rawDescData) - }) - return file_grpc_proto_messager_proto_rawDescData -} - -var ( - file_grpc_proto_messager_proto_msgTypes = make([]protoimpl.MessageInfo, 8) - file_grpc_proto_messager_proto_goTypes = []interface{}{ - (*StreamRequest)(nil), // 0: message.StreamRequest - (*StreamResponse)(nil), // 1: message.StreamResponse - (*RegisterRequest)(nil), // 2: message.RegisterRequest - (*RegisterResponse)(nil), // 3: message.RegisterResponse - (*SignOutRequest)(nil), // 4: message.SignOutRequest - (*SignOutResponse)(nil), // 5: message.SignOutResponse - nil, // 6: message.StreamRequest.DataEntry - nil, // 7: message.StreamResponse.DataEntry - } -) - -var file_grpc_proto_messager_proto_depIdxs = []int32{ - 6, // 0: message.StreamRequest.data:type_name -> message.StreamRequest.DataEntry - 7, // 1: message.StreamResponse.data:type_name -> message.StreamResponse.DataEntry - 2, // 2: message.Message.Register:input_type -> message.RegisterRequest - 4, // 3: message.Message.SignOut:input_type -> message.SignOutRequest - 0, // 4: message.Message.BidirectionalStreamingMessage:input_type -> message.StreamRequest - 3, // 5: message.Message.Register:output_type -> message.RegisterResponse - 5, // 6: message.Message.SignOut:output_type -> message.SignOutResponse - 1, // 7: message.Message.BidirectionalStreamingMessage:output_type -> message.StreamResponse - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_grpc_proto_messager_proto_init() } -func file_grpc_proto_messager_proto_init() { - if File_grpc_proto_messager_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_grpc_proto_messager_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_grpc_proto_messager_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_grpc_proto_messager_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_grpc_proto_messager_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_grpc_proto_messager_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignOutRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_grpc_proto_messager_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SignOutResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_grpc_proto_messager_proto_rawDesc, - NumEnums: 0, - NumMessages: 8, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_grpc_proto_messager_proto_goTypes, - DependencyIndexes: file_grpc_proto_messager_proto_depIdxs, - MessageInfos: file_grpc_proto_messager_proto_msgTypes, - }.Build() - File_grpc_proto_messager_proto = out.File - file_grpc_proto_messager_proto_rawDesc = nil - file_grpc_proto_messager_proto_goTypes = nil - file_grpc_proto_messager_proto_depIdxs = nil -} diff --git a/hrp/pkg/boomer/grpc/messager/messager_grpc.pb.go b/hrp/pkg/boomer/grpc/messager/messager_grpc.pb.go deleted file mode 100644 index 80e1a6b5..00000000 --- a/hrp/pkg/boomer/grpc/messager/messager_grpc.pb.go +++ /dev/null @@ -1,212 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.19.4 -// source: grpc/proto/messager.proto - -package messager - -import ( - context "context" - - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// MessageClient is the client API for Message service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type MessageClient interface { - Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) - SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error) - BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error) -} - -type messageClient struct { - cc grpc.ClientConnInterface -} - -func NewMessageClient(cc grpc.ClientConnInterface) MessageClient { - return &messageClient{cc} -} - -func (c *messageClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) { - out := new(RegisterResponse) - err := c.cc.Invoke(ctx, "/message.Message/Register", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *messageClient) SignOut(ctx context.Context, in *SignOutRequest, opts ...grpc.CallOption) (*SignOutResponse, error) { - out := new(SignOutResponse) - err := c.cc.Invoke(ctx, "/message.Message/SignOut", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *messageClient) BidirectionalStreamingMessage(ctx context.Context, opts ...grpc.CallOption) (Message_BidirectionalStreamingMessageClient, error) { - stream, err := c.cc.NewStream(ctx, &Message_ServiceDesc.Streams[0], "/message.Message/BidirectionalStreamingMessage", opts...) - if err != nil { - return nil, err - } - x := &messageBidirectionalStreamingMessageClient{stream} - return x, nil -} - -type Message_BidirectionalStreamingMessageClient interface { - Send(*StreamRequest) error - Recv() (*StreamResponse, error) - grpc.ClientStream -} - -type messageBidirectionalStreamingMessageClient struct { - grpc.ClientStream -} - -func (x *messageBidirectionalStreamingMessageClient) Send(m *StreamRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *messageBidirectionalStreamingMessageClient) Recv() (*StreamResponse, error) { - m := new(StreamResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// MessageServer is the server API for Message service. -// All implementations must embed UnimplementedMessageServer -// for forward compatibility -type MessageServer interface { - Register(context.Context, *RegisterRequest) (*RegisterResponse, error) - SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error) - BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error - mustEmbedUnimplementedMessageServer() -} - -// UnimplementedMessageServer must be embedded to have forward compatible implementations. -type UnimplementedMessageServer struct{} - -func (UnimplementedMessageServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") -} - -func (UnimplementedMessageServer) SignOut(context.Context, *SignOutRequest) (*SignOutResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method SignOut not implemented") -} - -func (UnimplementedMessageServer) BidirectionalStreamingMessage(Message_BidirectionalStreamingMessageServer) error { - return status.Errorf(codes.Unimplemented, "method BidirectionalStreamingMessage not implemented") -} -func (UnimplementedMessageServer) mustEmbedUnimplementedMessageServer() {} - -// UnsafeMessageServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to MessageServer will -// result in compilation errors. -type UnsafeMessageServer interface { - mustEmbedUnimplementedMessageServer() -} - -func RegisterMessageServer(s grpc.ServiceRegistrar, srv MessageServer) { - s.RegisterService(&Message_ServiceDesc, srv) -} - -func _Message_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RegisterRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MessageServer).Register(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/message.Message/Register", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MessageServer).Register(ctx, req.(*RegisterRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Message_SignOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SignOutRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MessageServer).SignOut(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/message.Message/SignOut", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MessageServer).SignOut(ctx, req.(*SignOutRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Message_BidirectionalStreamingMessage_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(MessageServer).BidirectionalStreamingMessage(&messageBidirectionalStreamingMessageServer{stream}) -} - -type Message_BidirectionalStreamingMessageServer interface { - Send(*StreamResponse) error - Recv() (*StreamRequest, error) - grpc.ServerStream -} - -type messageBidirectionalStreamingMessageServer struct { - grpc.ServerStream -} - -func (x *messageBidirectionalStreamingMessageServer) Send(m *StreamResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *messageBidirectionalStreamingMessageServer) Recv() (*StreamRequest, error) { - m := new(StreamRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// Message_ServiceDesc is the grpc.ServiceDesc for Message service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Message_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "message.Message", - HandlerType: (*MessageServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Register", - Handler: _Message_Register_Handler, - }, - { - MethodName: "SignOut", - Handler: _Message_SignOut_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "BidirectionalStreamingMessage", - Handler: _Message_BidirectionalStreamingMessage_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "grpc/proto/messager.proto", -} diff --git a/hrp/pkg/boomer/grpc/proto/messager.proto b/hrp/pkg/boomer/grpc/proto/messager.proto deleted file mode 100644 index 2dc77839..00000000 --- a/hrp/pkg/boomer/grpc/proto/messager.proto +++ /dev/null @@ -1,45 +0,0 @@ -syntax = "proto3"; - -package message; - -option go_package = "grpc/messager"; - -service Message { - rpc Register(RegisterRequest) returns (RegisterResponse) {} - rpc SignOut(SignOutRequest) returns (SignOutResponse) {} - rpc BidirectionalStreamingMessage(stream StreamRequest) returns (stream StreamResponse){}; -} - -message StreamRequest{ - string type = 1; - string nodeID = 2; - map data = 3; -} - -message StreamResponse{ - string type = 1; - string nodeID = 2; - bytes profile = 3; - bytes tasks = 4; - map data = 5; -} - -message RegisterRequest{ - string nodeID = 1; - string os = 2; - string arch = 3; -} - -message RegisterResponse{ - string code = 1; - string message = 2; -} - -message SignOutRequest{ - string nodeID = 1; -} - -message SignOutResponse{ - string code = 1; - string message = 2; -} \ No newline at end of file diff --git a/hrp/pkg/boomer/hrp/boomer.go b/hrp/pkg/boomer/hrp/boomer.go deleted file mode 100644 index 657e0761..00000000 --- a/hrp/pkg/boomer/hrp/boomer.go +++ /dev/null @@ -1,445 +0,0 @@ -package hrpboomer - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/httprunner/funplugin" - "github.com/rs/zerolog/log" - "golang.org/x/net/context" - - "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/code" - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" - "github.com/httprunner/httprunner/v4/hrp/internal/json" - "github.com/httprunner/httprunner/v4/hrp/internal/sdk" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer" -) - -var pluginMap sync.Map // used for reusing plugin instance - -func NewStandaloneBoomer(spawnCount int64, spawnRate float64) *HRPBoomer { - b := &HRPBoomer{ - Boomer: boomer.NewStandaloneBoomer(spawnCount, spawnRate), - pluginsMutex: new(sync.RWMutex), - } - - b.hrpRunner = hrp.NewRunner(nil) - return b -} - -func NewMasterBoomer(masterBindHost string, masterBindPort int) *HRPBoomer { - b := &HRPBoomer{ - Boomer: boomer.NewMasterBoomer(masterBindHost, masterBindPort), - pluginsMutex: new(sync.RWMutex), - } - b.hrpRunner = hrp.NewRunner(nil) - return b -} - -func NewWorkerBoomer(masterHost string, masterPort int) *HRPBoomer { - b := &HRPBoomer{ - Boomer: boomer.NewWorkerBoomer(masterHost, masterPort), - pluginsMutex: new(sync.RWMutex), - } - - b.hrpRunner = hrp.NewRunner(nil) - // set client transport for high concurrency load testing - b.hrpRunner.SetClientTransport(b.GetSpawnCount(), b.GetDisableKeepAlive(), b.GetDisableCompression()) - return b -} - -type HRPBoomer struct { - *boomer.Boomer - hrpRunner *hrp.HRPRunner - plugins []funplugin.IPlugin // each task has its own plugin process - pluginsMutex *sync.RWMutex // avoid data race -} - -func (b *HRPBoomer) InitBoomer() { - if !b.GetProfile().DisableConsoleOutput { - b.AddOutput(boomer.NewConsoleOutput()) - } - if b.GetProfile().PrometheusPushgatewayURL != "" { - b.AddOutput(boomer.NewPrometheusPusherOutput(b.GetProfile().PrometheusPushgatewayURL, "hrp", b.GetMode())) - } - b.SetSpawnCount(b.GetProfile().SpawnCount) - b.SetSpawnRate(b.GetProfile().SpawnRate) - b.SetRunTime(b.GetProfile().RunTime) - if b.GetProfile().LoopCount > 0 { - b.SetLoopCount(b.GetProfile().LoopCount) - } - b.SetRateLimiter(b.GetProfile().MaxRPS, b.GetProfile().RequestIncreaseRate) - b.SetDisableKeepAlive(b.GetProfile().DisableKeepalive) - b.SetDisableCompression(b.GetProfile().DisableCompression) - b.SetClientTransport() - b.EnableCPUProfile(b.GetProfile().CPUProfile, b.GetProfile().CPUProfileDuration) - b.EnableMemoryProfile(b.GetProfile().MemoryProfile, b.GetProfile().MemoryProfileDuration) -} - -func (b *HRPBoomer) SetClientTransport() *HRPBoomer { - // set client transport for high concurrency load testing - b.hrpRunner.SetClientTransport(b.GetSpawnCount(), b.GetDisableKeepAlive(), b.GetDisableCompression()) - return b -} - -// SetPython3Venv specifies python3 venv. -func (b *HRPBoomer) SetPython3Venv(venv string) *HRPBoomer { - b.hrpRunner.SetPython3Venv(venv) - return b -} - -// Run starts to run load test for one or multiple testcases. -func (b *HRPBoomer) Run(testcases ...hrp.ITestCase) { - startTime := time.Now() - defer func() { - // report boom event - sdk.SendGA4Event("hrp_boomer_run", map[string]interface{}{ - "engagement_time_msec": time.Since(startTime).Milliseconds(), - }) - - // quit all plugins - pluginMap.Range(func(key, value interface{}) bool { - if plugin, ok := value.(funplugin.IPlugin); ok { - plugin.Quit() - } - return true - }) - }() - - taskSlice := b.ConvertTestCasesToBoomerTasks(testcases...) - - b.Boomer.Run(taskSlice...) -} - -func (b *HRPBoomer) ConvertTestCasesToBoomerTasks(testcases ...hrp.ITestCase) (taskSlice []*boomer.Task) { - // load all testcases - testCases, err := hrp.LoadTestCases(testcases...) - if err != nil { - log.Error().Err(err).Msg("failed to load testcases") - os.Exit(code.GetErrorCode(err)) - } - - for _, testcase := range testCases { - rendezvousList := hrp.InitRendezvous(testcase, int64(b.GetSpawnCount())) - task := b.convertBoomerTask(testcase, rendezvousList) - taskSlice = append(taskSlice, task) - hrp.WaitRendezvous(rendezvousList, b) - } - return taskSlice -} - -func (b *HRPBoomer) ParseTestCases(testCases []*hrp.TestCase) []*hrp.TestCase { - var parsedTestCases []*hrp.TestCase - for _, tc := range testCases { - caseRunner, err := b.hrpRunner.NewCaseRunner(*tc) - if err != nil { - log.Error().Err(err).Msg("failed to create runner") - os.Exit(code.GetErrorCode(err)) - } - caseConfig := caseRunner.TestCase.Config.Get() - caseConfig.Parameters = caseRunner.GetParametersIterator().Data() - parsedTestCases = append(parsedTestCases, &hrp.TestCase{ - Config: caseConfig, - TestSteps: caseRunner.TestSteps, - }) - } - return parsedTestCases -} - -func (b *HRPBoomer) TestCasesToBytes(testcases ...hrp.ITestCase) []byte { - // load all testcases - testCases, err := hrp.LoadTestCases(testcases...) - if err != nil { - log.Error().Err(err).Msg("failed to load testcases") - os.Exit(code.GetErrorCode(err)) - } - testCasesBytes, err := json.Marshal(testCases) - if err != nil { - log.Error().Err(err).Msg("failed to marshal testcases") - return nil - } - return testCasesBytes -} - -func (b *HRPBoomer) BytesToTCases(testCasesBytes []byte) []*hrp.TestCase { - var testcase []*hrp.TestCase - err := json.Unmarshal(testCasesBytes, &testcase) - if err != nil { - log.Error().Err(err).Msg("failed to unmarshal testcases") - } - return testcase -} - -func (b *HRPBoomer) Quit() { - b.Boomer.Quit() -} - -func (b *HRPBoomer) parseTCases(testCases []*hrp.TestCase) (testcases []hrp.ITestCase) { - for _, tc := range testCases { - // create temp dir to save testcase - tempDir, err := os.MkdirTemp("", "hrp_testcases") - if err != nil { - log.Error().Err(err).Msg("failed to create hrp testcases directory") - return - } - - caseConfig := tc.Config.Get() - if caseConfig.PluginSetting != nil { - caseConfig.PluginSetting.Path = filepath.Join(tempDir, fmt.Sprintf("debugtalk.%s", caseConfig.PluginSetting.Type)) - err = builtin.Bytes2File(caseConfig.PluginSetting.Content, caseConfig.PluginSetting.Path) - if err != nil { - log.Error().Err(err).Msg("failed to save plugin file") - return - } - caseConfig.PluginSetting.Content = nil // remove the content in testcase - } - - if caseConfig.Environs != nil { - envContent := "" - for k, v := range caseConfig.Environs { - envContent += fmt.Sprintf("%s=%s\n", k, v) - } - err = os.WriteFile(filepath.Join(tempDir, ".env"), []byte(envContent), 0o644) - if err != nil { - log.Error().Err(err).Msg("failed to dump environs") - return - } - } - - caseConfig.Path = filepath.Join(tempDir, "test-case.json") - err = builtin.Dump2JSON(tc, caseConfig.Path) - if err != nil { - log.Error().Err(err).Msg("failed to dump testcases") - return - } - - testcases = append(testcases, tc) - } - return testcases -} - -func (b *HRPBoomer) initWorker(profile *boomer.Profile) { - // if no IP address is specified, the default IP address is that of the master - if profile.PrometheusPushgatewayURL != "" { - urlSlice := strings.Split(profile.PrometheusPushgatewayURL, ":") - if len(urlSlice) != 2 { - profile.PrometheusPushgatewayURL = "" - } else { - if urlSlice[0] == "" { - urlSlice[0] = b.Boomer.GetMasterHost() - } - } - profile.PrometheusPushgatewayURL = strings.Join(urlSlice, ":") - } - - b.SetProfile(profile) - b.InitBoomer() -} - -func (b *HRPBoomer) rebalanceRunner(profile *boomer.Profile) { - b.SetSpawnCount(profile.SpawnCount) - b.SetSpawnRate(profile.SpawnRate) - b.GetRebalanceChan() <- true - log.Info().Interface("profile", profile).Msg("rebalance tasks successfully") -} - -func (b *HRPBoomer) PollTasks(ctx context.Context) { - for { - select { - case task := <-b.Boomer.GetTasksChan(): - // 清理过时测试用例任务 - if len(b.Boomer.GetTasksChan()) > 0 { - continue - } - // Todo: 过滤掉已经传输过的task - if task.TestCasesBytes != nil { - // init boomer with profile - b.initWorker(task.Profile) - // get testcases - testcases := b.parseTCases(b.BytesToTCases(task.TestCasesBytes)) - log.Info().Interface("testcases", testcases).Interface("profile", b.GetProfile()).Msg("starting to run tasks") - // run testcases - go b.Run(testcases...) - } else { - // rebalance runner with profile - go b.rebalanceRunner(task.Profile) - } - - case <-b.Boomer.GetCloseChan(): - return - case <-ctx.Done(): - return - } - } -} - -func (b *HRPBoomer) PollTestCases(ctx context.Context) { - // quit all plugins - defer func() { - pluginMap.Range(func(key, value interface{}) bool { - if plugin, ok := value.(funplugin.IPlugin); ok { - plugin.Quit() - } - return true - }) - }() - - for { - select { - case <-b.Boomer.ParseTestCasesChan(): - var tcs []hrp.ITestCase - for _, tc := range b.GetTestCasesPath() { - tcp := hrp.TestCasePath(tc) - tcs = append(tcs, &tcp) - } - b.TestCaseBytesChan() <- b.TestCasesToBytes(tcs...) - log.Info().Msg("put testcase successfully") - case <-b.Boomer.GetCloseChan(): - return - case <-ctx.Done(): - return - } - } -} - -func (b *HRPBoomer) convertBoomerTask(testcase *hrp.TestCase, rendezvousList []*hrp.Rendezvous) *boomer.Task { - // init case runner for testcase - // this runner is shared by multiple session runners - caseRunner, err := b.hrpRunner.NewCaseRunner(*testcase) - if err != nil { - log.Error().Err(err).Msg("failed to create runner") - os.Exit(code.GetErrorCode(err)) - } - plugin := caseRunner.GetParser().Plugin - if plugin != nil { - b.pluginsMutex.Lock() - b.plugins = append(b.plugins, plugin) - b.pluginsMutex.Unlock() - } - - // broadcast to all rendezvous at once when spawn done - go func() { - <-b.GetSpawnDoneChan() - for _, rendezvous := range rendezvousList { - rendezvous.SetSpawnDone() - } - }() - - // set paramters mode for load testing - parametersIterator := caseRunner.GetParametersIterator() - parametersIterator.SetUnlimitedMode() - - // reset start time only once - once := sync.Once{} - - // update session variables mutex - mutex := sync.Mutex{} - - return &boomer.Task{ - Name: testcase.Config.Get().Name, - Weight: testcase.Config.Get().Weight, - Fn: func() { - testcaseSuccess := true // flag whole testcase result - transactionSuccess := true // flag current transaction result - - // init session runner - sessionRunner := caseRunner.NewSession() - - mutex.Lock() - if parametersIterator.HasNext() { - sessionRunner.InitWithParameters(parametersIterator.Next()) - } - mutex.Unlock() - - defer func() { - sessionRunner.ReleaseResources() - }() - - startTime := time.Now() - for _, step := range testcase.TestSteps { - // parse step struct - err = sessionRunner.ParseStep(step) - if err != nil { - log.Error().Err(err).Msg("parse step struct failed") - } - - // reset start time only once before step - once.Do(func() { - b.Boomer.ResetStartTime() - }) - stepResult, err := step.Run(sessionRunner) - // update step result name with parsed step name - stepResult.Name = step.Name() - // record requests result of the step if step type is testcase - if stepResult.StepType == hrp.StepTypeTestCase && stepResult.Data != nil { - // record requests of testcase step - for _, result := range stepResult.Data.([]*hrp.StepResult) { - if result.Success { - b.RecordSuccess(string(result.StepType), result.Name, result.Elapsed, result.ContentSize) - } else { - exception, _ := result.Attachments.(string) - b.RecordFailure(string(result.StepType), result.Name, result.Elapsed, exception) - } - } - } - // record step failure - if err != nil { - // step failed - var elapsed int64 - if stepResult != nil { - elapsed = stepResult.Elapsed - } - b.RecordFailure(string(step.Type()), stepResult.Name, elapsed, err.Error()) - - // update flag - testcaseSuccess = false - transactionSuccess = false - - log.Warn().Err(err).Msg("run step failed, continue next step") - continue - } - - // record step success - if stepResult.StepType == hrp.StepTypeTransaction { - // transaction - // FIXME: support nested transactions - stepTransaction := step.(*hrp.StepTransaction) - if stepTransaction.Transaction.Type == hrp.TransactionEnd { // only record when transaction ends - b.RecordTransaction(stepTransaction.Name(), transactionSuccess, stepResult.Elapsed, 0) - transactionSuccess = true // reset flag for next transaction - } - } else if stepResult.StepType == hrp.StepTypeRendezvous { - // rendezvous - } else if stepResult.StepType == hrp.StepTypeThinkTime { - // think time - // no record required - } else { - // request or testcase step - b.RecordSuccess(string(step.Type()), stepResult.Name, stepResult.Elapsed, stepResult.ContentSize) - // update extracted variables - for k, v := range stepResult.ExportVars { - sessionRunner.GetSessionVariables()[k] = v - } - } - } - endTime := time.Now() - - // report duration for transaction without end - for name, transaction := range sessionRunner.GetTransactions() { - if len(transaction) == 1 { - // if transaction end time not exists, use testcase end time instead - duration := endTime.Sub(transaction[hrp.TransactionStart]) - b.RecordTransaction(name, transactionSuccess, duration.Milliseconds(), 0) - } - } - - // report testcase as a whole Action transaction, inspired by LoadRunner - b.RecordTransaction("Action", testcaseSuccess, endTime.Sub(startTime).Milliseconds(), 0) - }, - } -} diff --git a/hrp/pkg/boomer/hrp/boomer_server.go b/hrp/pkg/boomer/hrp/boomer_server.go deleted file mode 100644 index cf8ca5c5..00000000 --- a/hrp/pkg/boomer/hrp/boomer_server.go +++ /dev/null @@ -1,381 +0,0 @@ -package hrpboomer - -import ( - "context" - "errors" - "fmt" - "io" - "log" - "net/http" - "strings" - - "github.com/mitchellh/mapstructure" - - "github.com/httprunner/httprunner/v4/hrp/internal/json" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer" -) - -const jsonContentType = "application/json; encoding=utf-8" - -func methods(h http.HandlerFunc, methods ...string) http.HandlerFunc { - methodMap := make(map[string]struct{}, len(methods)) - for _, m := range methods { - methodMap[m] = struct{}{} - // GET implies support for HEAD - if m == "GET" { - methodMap["HEAD"] = struct{}{} - } - } - return func(w http.ResponseWriter, r *http.Request) { - if _, ok := methodMap[r.Method]; !ok { - http.Error(w, fmt.Sprintf("method %s not allowed", r.Method), http.StatusMethodNotAllowed) - return - } - h.ServeHTTP(w, r) - } -} - -func parseBody(r *http.Request) (data map[string]interface{}, err error) { - if r.Body == nil { - return nil, nil - } - - // Always set resp.Data to the incoming request body, in case we don't know - // how to handle the content type - body, err := io.ReadAll(r.Body) - if err != nil { - r.Body.Close() - return nil, err - } - err = json.Unmarshal(body, &data) - if err != nil { - return nil, err - } - return data, nil -} - -func writeJSON(w http.ResponseWriter, body []byte, status int) { - w.Header().Set("Content-Type", jsonContentType) - w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body))) - w.WriteHeader(status) - w.Write(body) -} - -type ServerCode int - -// server response code -const ( - Success ServerCode = iota - ParamsError - ServerError - StopError -) - -// ServerStatus stores http response code and message -type ServerStatus struct { - Code ServerCode `json:"code"` - Message string `json:"message"` -} - -var EnumAPIResponseSuccess = ServerStatus{ - Code: Success, - Message: "success", -} - -func EnumAPIResponseParamError(errMsg string) ServerStatus { - return ServerStatus{ - Code: ParamsError, - Message: errMsg, - } -} - -func EnumAPIResponseServerError(errMsg string) ServerStatus { - return ServerStatus{ - Code: ServerError, - Message: errMsg, - } -} - -func EnumAPIResponseStopError(errMsg string) ServerStatus { - return ServerStatus{ - Code: StopError, - Message: errMsg, - } -} - -func CustomAPIResponse(errCode ServerCode, errMsg string) ServerStatus { - return ServerStatus{ - Code: errCode, - Message: errMsg, - } -} - -type StartRequestBody struct { - boomer.Profile `mapstructure:",squash"` - Worker string `json:"worker,omitempty" yaml:"worker,omitempty" mapstructure:"worker"` // all - TestCasePath string `json:"testcase-path" yaml:"testcase-path" mapstructure:"testcase-path"` - Other map[string]interface{} `mapstructure:",remain"` -} - -type RebalanceRequestBody struct { - boomer.Profile `mapstructure:",squash"` - Worker string `json:"worker,omitempty" yaml:"worker,omitempty" mapstructure:"worker"` - Other map[string]interface{} `mapstructure:",remain"` -} - -type StopRequestBody struct { - Worker string `json:"worker"` -} - -type QuitRequestBody struct { - Worker string `json:"worker"` -} - -type CommonResponseBody struct { - ServerStatus -} - -type APIGetWorkersRequestBody struct{} - -type APIGetWorkersResponseBody struct { - ServerStatus - Data []boomer.WorkerNode `json:"data"` -} - -type APIGetMasterRequestBody struct{} - -type APIGetMasterResponseBody struct { - ServerStatus - Data map[string]interface{} `json:"data"` -} - -type apiHandler struct { - boomer *HRPBoomer -} - -func (b *HRPBoomer) NewAPIHandler() *apiHandler { - return &apiHandler{boomer: b} -} - -// Index renders an HTML index page -func (api *apiHandler) Index(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/" { - http.Error(w, "Not Found", http.StatusNotFound) - return - } - w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' www.httprunner.com") - fmt.Fprintf(w, "Welcome to httprunner page!") -} - -func (api *apiHandler) Start(w http.ResponseWriter, r *http.Request) { - var resp *CommonResponseBody - var err error - defer func() { - if err != nil { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseServerError(err.Error()), - } - } else { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - } - } - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) - }() - - // parse body - data, err := parseBody(r) - if err != nil { - return - } - req := StartRequestBody{ - Profile: *boomer.NewProfile(), - } - err = mapstructure.Decode(data, &req) - if err != nil { - return - } - - // recognize invalid parameters - if len(req.Other) > 0 { - keys := make([]string, 0, len(req.Other)) - for k := range req.Other { - keys = append(keys, k) - } - err = fmt.Errorf("failed to recognize params: %v", keys) - return - } - - // parse testcase path - if req.TestCasePath == "" { - err = errors.New("missing testcases path") - return - } - paths := strings.Split(req.TestCasePath, ",") - - // set testcase path - api.boomer.SetTestCasesPath(paths) - - // start boomer with profile - err = api.boomer.Start(&req.Profile) -} - -func (api *apiHandler) ReBalance(w http.ResponseWriter, r *http.Request) { - var resp *CommonResponseBody - var err error - defer func() { - if err != nil { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseServerError(err.Error()), - } - } else { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - } - } - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) - }() - - // parse body - data, err := parseBody(r) - if err != nil { - return - } - req := RebalanceRequestBody{ - Profile: *api.boomer.GetProfile(), - } - err = mapstructure.Decode(data, &req) - if err != nil { - return - } - - // recognize invalid parameters - if len(req.Other) > 0 { - keys := make([]string, 0, len(req.Other)) - for k := range req.Other { - keys = append(keys, k) - } - err = fmt.Errorf("failed to recognize params: %v", keys) - return - } - - // rebalance boomer with profile - err = api.boomer.ReBalance(&req.Profile) -} - -func (api *apiHandler) Stop(w http.ResponseWriter, r *http.Request) { - data := map[string]interface{}{} - args := r.URL.Query() - for k, vs := range args { - for _, v := range vs { - data[k] = v - } - } - - var resp *CommonResponseBody - var err error - defer func() { - if err != nil { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseStopError(err.Error()), - } - } else { - resp = &CommonResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - } - } - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) - }() - - // stop boomer - err = api.boomer.Stop() -} - -func (api *apiHandler) Quit(w http.ResponseWriter, r *http.Request) { - data := map[string]interface{}{} - args := r.URL.Query() - for k, vs := range args { - for _, v := range vs { - data[k] = v - } - } - defer func() { - resp := &CommonResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - } - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) - }() - - // quit boomer - api.boomer.Quit() -} - -func (api *apiHandler) GetWorkersInfo(w http.ResponseWriter, r *http.Request) { - resp := &APIGetWorkersResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - Data: api.boomer.GetWorkersInfo(), - } - - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) -} - -func (api *apiHandler) GetMasterInfo(w http.ResponseWriter, r *http.Request) { - resp := &APIGetMasterResponseBody{ - ServerStatus: EnumAPIResponseSuccess, - Data: api.boomer.GetMasterInfo(), - } - - body, _ := json.Marshal(resp) - writeJSON(w, body, http.StatusOK) -} - -func (api *apiHandler) Handler() http.Handler { - mux := http.NewServeMux() - - mux.HandleFunc("/", methods(api.Index, "GET")) - mux.HandleFunc("/start", methods(api.Start, "POST")) - mux.HandleFunc("/rebalance", methods(api.ReBalance, "POST")) - mux.HandleFunc("/stop", methods(api.Stop, "GET")) - mux.HandleFunc("/quit", methods(api.Quit, "GET")) - mux.HandleFunc("/workers", methods(api.GetWorkersInfo, "GET")) - mux.HandleFunc("/master", methods(api.GetMasterInfo, "GET")) - - return mux -} - -func (apiHandler) ServeHTTP(http.ResponseWriter, *http.Request) {} - -func (b *HRPBoomer) StartServer(ctx context.Context, addr string) { - h := b.NewAPIHandler() - mux := h.Handler() - - server := &http.Server{ - Addr: addr, - Handler: mux, - } - - go func() { - select { - case <-ctx.Done(): - case <-b.GetCloseChan(): - } - if err := server.Shutdown(context.Background()); err != nil { - log.Fatal("shutdown server:", err) - } - }() - - log.Printf("starting HTTP server (%v), please use the API to control master", server.Addr) - err := server.ListenAndServe() - if err != nil { - if err == http.ErrServerClosed { - log.Print("server closed under request") - } else { - log.Fatal("server closed unexpected") - } - } -} diff --git a/hrp/pkg/boomer/hrp/boomer_test.go b/hrp/pkg/boomer/hrp/boomer_test.go deleted file mode 100644 index 314de133..00000000 --- a/hrp/pkg/boomer/hrp/boomer_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package hrpboomer - -import ( - "testing" - "time" - - "github.com/httprunner/httprunner/v4/hrp" -) - -func TestBoomerStandaloneRun(t *testing.T) { - testcase1 := &hrp.TestCase{ - Config: hrp.NewConfig("TestCase1").SetBaseURL("https://postman-echo.com"), - TestSteps: []hrp.IStep{ - hrp.NewStep("headers"). - GET("/headers"). - Validate(). - AssertEqual("status_code", 200, "check status code"). - AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"), - hrp.NewStep("user-agent"). - GET("/user-agent"). - Validate(). - AssertEqual("status_code", 200, "check status code"). - AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"), - hrp.NewStep("TestCase3").CallRefCase(&hrp.TestCase{Config: hrp.NewConfig("TestCase3")}), - }, - } - - b := NewStandaloneBoomer(2, 1) - go b.Run(testcase1) - time.Sleep(5 * time.Second) - b.Quit() -} diff --git a/hrp/pkg/boomer/hrp/cli/boom.go b/hrp/pkg/boomer/hrp/cli/boom.go deleted file mode 100644 index 8ee1e018..00000000 --- a/hrp/pkg/boomer/hrp/cli/boom.go +++ /dev/null @@ -1,147 +0,0 @@ -package main - -import ( - "strings" - "time" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "github.com/spf13/cobra" - "golang.org/x/net/context" - - "github.com/httprunner/httprunner/v4/hrp" - "github.com/httprunner/httprunner/v4/hrp/internal/sdk" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer" - hrpboomer "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/hrp" -) - -// boomCmd represents the boom command -var boomCmd = &cobra.Command{ - Use: "boom", - Short: "run load test with boomer", - Long: `run yaml/json testcase files for load test`, - Example: ` $ hrp boom demo.json # run specified json testcase file - $ hrp boom demo.yaml # run specified yaml testcase file - $ hrp boom examples/ # run testcases in specified folder`, - Args: cobra.MinimumNArgs(0), - PreRun: func(cmd *cobra.Command, args []string) { - boomer.SetUlimit(10240) // ulimit -n 10240 - // disable info logs for load testing - log.Info().Msg("Set global log level to WARN for load testing") - zerolog.SetGlobalLevel(zerolog.WarnLevel) - }, - RunE: func(cmd *cobra.Command, args []string) (err error) { - startTime := time.Now() - defer func() { - sdk.SendGA4Event("hrp_boom", map[string]interface{}{ - "args": strings.Join(args, "-"), - "success": err == nil, - "engagement_time_msec": time.Since(startTime).Milliseconds(), - }) - }() - - var paths []hrp.ITestCase - for _, arg := range args { - path := hrp.TestCasePath(arg) - paths = append(paths, &path) - } - - // if set profile, the priority is higher than the other commands - if boomArgs.profile != "" { - err := hrp.LoadFileObject(boomArgs.profile, &boomArgs.Profile) - if err != nil { - log.Error().Err(err).Msg("failed to load profile") - return err - } - } - - // init boomer - var hrpBoomer *hrpboomer.HRPBoomer - if boomArgs.master { - hrpBoomer = hrpboomer.NewMasterBoomer(boomArgs.masterBindHost, boomArgs.masterBindPort) - } else if boomArgs.worker { - hrpBoomer = hrpboomer.NewWorkerBoomer(boomArgs.masterHost, boomArgs.masterPort) - } else { - hrpBoomer = hrpboomer.NewStandaloneBoomer(boomArgs.SpawnCount, boomArgs.SpawnRate) - } - hrpBoomer.SetProfile(&boomArgs.Profile) - ctx := hrpBoomer.EnableGracefulQuit(context.Background()) - - // run boomer - switch hrpBoomer.GetMode() { - case "master": - hrpBoomer.SetTestCasesPath(args) - if boomArgs.autoStart { - hrpBoomer.SetAutoStart() - hrpBoomer.SetExpectWorkers(boomArgs.expectWorkers, boomArgs.expectWorkersMaxWait) - hrpBoomer.SetSpawnCount(boomArgs.SpawnCount) - hrpBoomer.SetSpawnRate(boomArgs.SpawnRate) - hrpBoomer.SetRunTime(boomArgs.RunTime) - } - if boomArgs.autoStart { - hrpBoomer.InitBoomer() - } else { - go hrpBoomer.StartServer(ctx, boomArgs.masterHttpAddress) - } - go hrpBoomer.PollTestCases(ctx) - hrpBoomer.RunMaster() - case "worker": - if boomArgs.ignoreQuit { - hrpBoomer.SetIgnoreQuit() - } - go hrpBoomer.PollTasks(ctx) - hrpBoomer.RunWorker() - case "standalone": - hrpBoomer.InitBoomer() - hrpBoomer.Run(paths...) - } - return nil - }, -} - -type BoomArgs struct { - boomer.Profile - profile string - master bool - worker bool - ignoreQuit bool - masterHost string - masterPort int - masterBindHost string - masterBindPort int - masterHttpAddress string - autoStart bool - expectWorkers int - expectWorkersMaxWait int -} - -var boomArgs BoomArgs - -func init() { - boomCmd.Flags().Int64Var(&boomArgs.MaxRPS, "max-rps", 0, "Max RPS that boomer can generate, disabled by default.") - boomCmd.Flags().StringVar(&boomArgs.RequestIncreaseRate, "request-increase-rate", "-1", "Request increase rate, disabled by default.") - boomCmd.Flags().Int64Var(&boomArgs.SpawnCount, "spawn-count", 1, "The number of users to spawn for load testing") - boomCmd.Flags().Float64Var(&boomArgs.SpawnRate, "spawn-rate", 1, "The rate for spawning users") - boomCmd.Flags().Int64Var(&boomArgs.RunTime, "run-time", 0, "Stop after the specified amount of time(s), Only used --autostart. Defaults to run forever.") - boomCmd.Flags().Int64Var(&boomArgs.LoopCount, "loop-count", -1, "The specify running cycles for load testing") - boomCmd.Flags().StringVar(&boomArgs.MemoryProfile, "mem-profile", "", "Enable memory profiling.") - boomCmd.Flags().DurationVar(&boomArgs.MemoryProfileDuration, "mem-profile-duration", 30*time.Second, "Memory profile duration.") - boomCmd.Flags().StringVar(&boomArgs.CPUProfile, "cpu-profile", "", "Enable CPU profiling.") - boomCmd.Flags().DurationVar(&boomArgs.CPUProfileDuration, "cpu-profile-duration", 30*time.Second, "CPU profile duration.") - boomCmd.Flags().StringVar(&boomArgs.PrometheusPushgatewayURL, "prometheus-gateway", "", "Prometheus Pushgateway url.") - boomCmd.Flags().BoolVar(&boomArgs.DisableConsoleOutput, "disable-console-output", false, "Disable console output.") - boomCmd.Flags().BoolVar(&boomArgs.DisableCompression, "disable-compression", false, "Disable compression") - boomCmd.Flags().BoolVar(&boomArgs.DisableKeepalive, "disable-keepalive", false, "Disable keepalive") - boomCmd.Flags().StringVar(&boomArgs.profile, "profile", "", "profile for load testing") - boomCmd.Flags().BoolVar(&boomArgs.master, "master", false, "master of distributed testing") - boomCmd.Flags().StringVar(&boomArgs.masterBindHost, "master-bind-host", "127.0.0.1", "Interfaces (hostname, ip) that hrp master should bind to. Only used when running with --master. Defaults to * (all available interfaces).") - boomCmd.Flags().IntVar(&boomArgs.masterBindPort, "master-bind-port", 5557, "Port that hrp master should bind to. Only used when running with --master. Defaults to 5557.") - boomCmd.Flags().StringVar(&boomArgs.masterHttpAddress, "master-http-address", ":9771", "Interfaces (ip:port) that hrp master should control by user. Only used when running with --master. Defaults to *:9771.") - boomCmd.Flags().BoolVar(&boomArgs.worker, "worker", false, "worker of distributed testing") - boomCmd.Flags().BoolVar(&boomArgs.ignoreQuit, "ignore-quit", false, "ignores quit from master (only when --worker is used)") - boomCmd.Flags().StringVar(&boomArgs.masterHost, "master-host", "127.0.0.1", "Host or IP address of hrp master for distributed load testing.") - boomCmd.Flags().IntVar(&boomArgs.masterPort, "master-port", 5557, "The port to connect to that is used by the hrp master for distributed load testing.") - boomCmd.Flags().BoolVar(&boomArgs.autoStart, "auto-start", false, "Starts the test immediately. Use --spawn-count and --spawn-rate to control user count and increase rate") - boomCmd.Flags().IntVar(&boomArgs.expectWorkers, "expect-workers", 1, "How many workers master should expect to connect before starting the test (only when --autostart is used)") - boomCmd.Flags().IntVar(&boomArgs.expectWorkersMaxWait, "expect-workers-max-wait", 120, "How many workers master should expect to connect before starting the test (only when --autostart is used") -} diff --git a/hrp/pkg/boomer/hrp/cli/main.go b/hrp/pkg/boomer/hrp/cli/main.go deleted file mode 100644 index ad4d2045..00000000 --- a/hrp/pkg/boomer/hrp/cli/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "time" - - "github.com/getsentry/sentry-go" -) - -func main() { - defer func() { - if err := recover(); err != nil { - // report panic to sentry - sentry.CurrentHub().Recover(err) - sentry.Flush(time.Second * 5) - - // print panic trace - panic(err) - } - }() - - boomCmd.Execute() -} diff --git a/hrp/pkg/boomer/message.go b/hrp/pkg/boomer/message.go deleted file mode 100644 index ab6ae062..00000000 --- a/hrp/pkg/boomer/message.go +++ /dev/null @@ -1,55 +0,0 @@ -package boomer - -const ( - typeClientReady = "client_ready" - typeClientStopped = "client_stopped" - typeHeartbeat = "heartbeat" - typeSpawning = "spawning" - typeSpawningComplete = "spawning_complete" - typeQuit = "quit" - typeException = "exception" -) - -type genericMessage struct { - Type string `json:"type,omitempty"` - Profile []byte `json:"profile,omitempty"` - Data map[string][]byte `json:"data,omitempty"` - NodeID string `json:"node_id,omitempty"` - Tasks []byte `json:"tasks,omitempty"` -} - -type task struct { - Profile *Profile `json:"profile,omitempty"` - TestCasesBytes []byte `json:"testcases,omitempty"` -} - -func newGenericMessage(t string, data map[string][]byte, nodeID string) (msg *genericMessage) { - return &genericMessage{ - Type: t, - Data: data, - NodeID: nodeID, - } -} - -func newQuitMessage(nodeID string) (msg *genericMessage) { - return &genericMessage{ - Type: "quit", - NodeID: nodeID, - } -} - -func newMessageToWorker(t string, profile []byte, data map[string][]byte, tasks []byte) (msg *genericMessage) { - return &genericMessage{ - Type: t, - Profile: profile, - Data: data, - Tasks: tasks, - } -} - -func newClientReadyMessageToMaster(nodeID string) (msg *genericMessage) { - return &genericMessage{ - Type: "client_ready", - NodeID: nodeID, - } -} diff --git a/hrp/pkg/boomer/message_test.go b/hrp/pkg/boomer/message_test.go deleted file mode 100644 index 853e847e..00000000 --- a/hrp/pkg/boomer/message_test.go +++ /dev/null @@ -1 +0,0 @@ -package boomer diff --git a/hrp/pkg/boomer/output.go b/hrp/pkg/boomer/output.go deleted file mode 100644 index 0a3b7de3..00000000 --- a/hrp/pkg/boomer/output.go +++ /dev/null @@ -1,645 +0,0 @@ -package boomer - -import ( - "fmt" - "math" - "os" - "sort" - "strconv" - "sync" - "time" - - "github.com/olekukonko/tablewriter" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/push" - "github.com/rs/zerolog/log" - uuid "github.com/satori/go.uuid" - - "github.com/httprunner/httprunner/v4/hrp/internal/json" -) - -// Output is primarily responsible for printing test results to different destinations -// such as consoles, files. You can write you own output and add to boomer. -// When running in standalone mode, the default output is ConsoleOutput, you can add more. -// When running in distribute mode, test results will be reported to master with or without -// an output. -// All the OnXXX function will be call in a separated goroutine, just in case some output will block. -// But it will wait for all outputs return to avoid data lost. -type Output interface { - // OnStart will be call before the test starts. - OnStart() - - // By default, each output receive stats data from runner every three seconds. - // OnEvent is responsible for dealing with the data. - OnEvent(data map[string]interface{}) - - // OnStop will be called before the test ends. - OnStop() -} - -// ConsoleOutput is the default output for standalone mode. -type ConsoleOutput struct{} - -// NewConsoleOutput returns a ConsoleOutput. -func NewConsoleOutput() *ConsoleOutput { - return &ConsoleOutput{} -} - -func getMedianResponseTime(numRequests int64, responseTimes map[int64]int64) int64 { - medianResponseTime := int64(0) - if len(responseTimes) != 0 { - pos := (numRequests - 1) / 2 - var sortedKeys []int64 - for k := range responseTimes { - sortedKeys = append(sortedKeys, k) - } - sort.Slice(sortedKeys, func(i, j int) bool { - return sortedKeys[i] < sortedKeys[j] - }) - for _, k := range sortedKeys { - if pos < responseTimes[k] { - medianResponseTime = k - break - } - pos -= responseTimes[k] - } - } - return medianResponseTime -} - -func getAvgResponseTime(numRequests int64, totalResponseTime int64) (avgResponseTime float64) { - avgResponseTime = float64(0) - if numRequests != 0 { - avgResponseTime = float64(totalResponseTime) / float64(numRequests) - } - return avgResponseTime -} - -func getAvgContentLength(numRequests int64, totalContentLength int64) (avgContentLength int64) { - avgContentLength = int64(0) - if numRequests != 0 { - avgContentLength = totalContentLength / numRequests - } - return avgContentLength -} - -func getCurrentRps(numRequests int64, duration float64) (currentRps float64) { - currentRps = float64(numRequests) / duration - return currentRps -} - -func getCurrentFailPerSec(numFailures int64, duration float64) (currentFailPerSec float64) { - currentFailPerSec = float64(numFailures) / duration - return currentFailPerSec -} - -func getTotalFailRatio(totalRequests, totalFailures int64) (failRatio float64) { - if totalRequests == 0 { - return 0 - } - return float64(totalFailures) / float64(totalRequests) -} - -// OnStart of ConsoleOutput has nothing to do. -func (o *ConsoleOutput) OnStart() { -} - -// OnStop of ConsoleOutput has nothing to do. -func (o *ConsoleOutput) OnStop() { -} - -// OnEvent will print to the console. -func (o *ConsoleOutput) OnEvent(data map[string]interface{}) { - output, err := convertData(data) - if err != nil { - log.Error().Err(err).Msg("failed to convert data") - return - } - - state := getStateName(output.State) - - currentTime := time.Now() - println(fmt.Sprintf("Current time: %s, Users: %d, State: %s, Total RPS: %.1f, Total Average Response Time: %.1fms, Total Fail Ratio: %.1f%%", - currentTime.Format("2006/01/02 15:04:05"), output.UserCount, state, output.TotalRPS, output.TotalAvgResponseTime, output.TotalFailRatio*100)) - println(fmt.Sprintf("Accumulated Transactions: %d Passed, %d Failed", - output.TransactionsPassed, output.TransactionsFailed)) - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Type", "Name", "# requests", "# fails", "Median", "Average", "Min", "Max", "Content Size", "# reqs/sec", "# fails/sec"}) - - for _, stat := range output.Stats { - row := make([]string, 11) - row[0] = stat.Method - row[1] = stat.Name - row[2] = strconv.FormatInt(stat.NumRequests, 10) - row[3] = strconv.FormatInt(stat.NumFailures, 10) - row[4] = strconv.FormatInt(stat.medianResponseTime, 10) - row[5] = strconv.FormatFloat(stat.avgResponseTime, 'f', 2, 64) - row[6] = strconv.FormatInt(stat.MinResponseTime, 10) - row[7] = strconv.FormatInt(stat.MaxResponseTime, 10) - row[8] = strconv.FormatInt(stat.avgContentLength, 10) - row[9] = strconv.FormatFloat(stat.currentRps, 'f', 2, 64) - row[10] = strconv.FormatFloat(stat.currentFailPerSec, 'f', 2, 64) - table.Append(row) - } - table.Render() - println() -} - -type statsEntryOutput struct { - statsEntry - - medianResponseTime int64 // median response time - avgResponseTime float64 // average response time, round float to 2 decimal places - avgContentLength int64 // average content size - currentRps float64 // # reqs/sec - currentFailPerSec float64 // # fails/sec - duration float64 // the duration of stats -} - -type dataOutput struct { - UserCount int64 `json:"user_count"` - State int32 `json:"state"` - TotalStats *statsEntryOutput `json:"stats_total"` - TransactionsPassed int64 `json:"transactions_passed"` - TransactionsFailed int64 `json:"transactions_failed"` - TotalAvgResponseTime float64 `json:"total_avg_response_time"` - TotalMinResponseTime float64 `json:"total_min_response_time"` - TotalMaxResponseTime float64 `json:"total_max_response_time"` - TotalRPS float64 `json:"total_rps"` - TotalFailRatio float64 `json:"total_fail_ratio"` - TotalFailPerSec float64 `json:"total_fail_per_sec"` - Duration float64 `json:"duration"` - Stats []*statsEntryOutput `json:"stats"` - Errors map[string]map[string]interface{} `json:"errors"` -} - -func convertData(data map[string]interface{}) (output *dataOutput, err error) { - userCount, ok := data["user_count"].(int64) - if !ok { - return nil, fmt.Errorf("user_count is not int32") - } - state, ok := data["state"].(int32) - if !ok { - return nil, fmt.Errorf("state is not int32") - } - stats, ok := data["stats"].([]interface{}) - if !ok { - return nil, fmt.Errorf("stats is not []interface{}") - } - - errors := data["errors"].(map[string]map[string]interface{}) - - transactions, ok := data["transactions"].(map[string]int64) - if !ok { - return nil, fmt.Errorf("transactions is not map[string]int64") - } - transactionsPassed := transactions["passed"] - transactionsFailed := transactions["failed"] - - // convert stats in total - statsTotal, ok := data["stats_total"].(interface{}) - if !ok { - return nil, fmt.Errorf("stats_total is not interface{}") - } - entryTotalOutput, err := deserializeStatsEntry(statsTotal) - if err != nil { - return nil, err - } - - output = &dataOutput{ - UserCount: userCount, - State: state, - Duration: entryTotalOutput.duration, - TotalStats: entryTotalOutput, - TransactionsPassed: transactionsPassed, - TransactionsFailed: transactionsFailed, - TotalAvgResponseTime: entryTotalOutput.avgResponseTime, - TotalMaxResponseTime: float64(entryTotalOutput.MaxResponseTime), - TotalMinResponseTime: float64(entryTotalOutput.MinResponseTime), - TotalRPS: entryTotalOutput.currentRps, - TotalFailRatio: getTotalFailRatio(entryTotalOutput.NumRequests, entryTotalOutput.NumFailures), - TotalFailPerSec: entryTotalOutput.currentFailPerSec, - Stats: make([]*statsEntryOutput, 0, len(stats)), - Errors: errors, - } - - // convert stats - for _, stat := range stats { - entryOutput, err := deserializeStatsEntry(stat) - if err != nil { - return nil, err - } - output.Stats = append(output.Stats, entryOutput) - } - // sort stats by type - sort.Slice(output.Stats, func(i, j int) bool { - return output.Stats[i].Method < output.Stats[j].Method - }) - return -} - -func deserializeStatsEntry(stat interface{}) (entryOutput *statsEntryOutput, err error) { - statBytes, err := json.Marshal(stat) - if err != nil { - return nil, err - } - entry := statsEntry{} - if err = json.Unmarshal(statBytes, &entry); err != nil { - return nil, err - } - - var duration float64 - if entry.Name == "Total" { - duration = float64(entry.LastRequestTimestamp-entry.StartTime) / 1e3 - if duration == 0 { - return nil, errors.New("no step specified") - } - } else { - duration = float64(reportStatsInterval / time.Second) - } - - numRequests := entry.NumRequests - entryOutput = &statsEntryOutput{ - statsEntry: entry, - duration: duration, - medianResponseTime: getMedianResponseTime(numRequests, entry.ResponseTimes), - avgResponseTime: getAvgResponseTime(numRequests, entry.TotalResponseTime), - avgContentLength: getAvgContentLength(numRequests, entry.TotalContentLength), - currentRps: getCurrentRps(numRequests, duration), - currentFailPerSec: getCurrentFailPerSec(entry.NumFailures, duration), - } - return -} - -// gauge vectors for requests -var ( - gaugeNumRequests = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "num_requests", - Help: "The number of requests", - }, - []string{"method", "name"}, - ) - gaugeNumFailures = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "num_failures", - Help: "The number of failures", - }, - []string{"method", "name"}, - ) - gaugeMedianResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "median_response_time", - Help: "The median response time", - }, - []string{"method", "name"}, - ) - gaugeAverageResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "average_response_time", - Help: "The average response time", - }, - []string{"method", "name"}, - ) - gaugeMinResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "min_response_time", - Help: "The min response time", - }, - []string{"method", "name"}, - ) - gaugeMaxResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "max_response_time", - Help: "The max response time", - }, - []string{"method", "name"}, - ) - gaugeAverageContentLength = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "average_content_length", - Help: "The average content length", - }, - []string{"method", "name"}, - ) - gaugeCurrentRPS = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "current_rps", - Help: "The current requests per second", - }, - []string{"method", "name"}, - ) - gaugeCurrentFailPerSec = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "current_fail_per_sec", - Help: "The current failure number per second", - }, - []string{"method", "name"}, - ) -) - -// counter for total -var ( - counterErrors = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "errors", - Help: "The errors of load testing", - }, - []string{"method", "name", "error"}, - ) - counterTotalNumRequests = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "total_num_requests", - Help: "The number of requests in total", - }, - []string{"method", "name"}, - ) - counterTotalNumFailures = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "total_num_failures", - Help: "The number of failures in total", - }, - []string{"method", "name"}, - ) -) - -// summary for total -var ( - summaryResponseTime = prometheus.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "response_time", - Help: "The summary of response time", - Objectives: map[float64]float64{ - 0.5: 0.01, // PCT50 - 0.9: 0.01, // PCT90 - 0.95: 0.005, // PCT95 - }, - AgeBuckets: 1, - MaxAge: 100000 * time.Second, - }, - []string{"method", "name"}, - ) -) - -// gauges for total -var ( - gaugeUsers = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "users", - Help: "The current number of users", - }, - ) - gaugeState = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "state", - Help: "The current runner state, 1=initializing, 2=spawning, 3=running, 4=stopping, 5=stopped, 6=quitting, 7=missing", - }, - ) - gaugeDuration = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "duration", - Help: "The duration of load testing", - }, - ) - gaugeTotalAverageResponseTime = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "total_average_response_time", - Help: "The average response time in total milliseconds", - }, - ) - gaugeTotalMinResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "total_min_response_time", - Help: "The min response time in total milliseconds", - }, - []string{"method", "name"}, - ) - gaugeTotalMaxResponseTime = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "total_max_response_time", - Help: "The max response time in total milliseconds", - }, - []string{"method", "name"}, - ) - gaugeTotalRPS = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "total_rps", - Help: "The requests per second in total", - }, - ) - gaugeTotalFailRatio = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "fail_ratio", - Help: "The ratio of request failures in total", - }, - ) - gaugeTotalFailPerSec = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "total_fail_per_sec", - Help: "The failure number per second in total", - }, - ) - gaugeTransactionsPassed = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "transactions_passed", - Help: "The accumulated number of passed transactions", - }, - ) - gaugeTransactionsFailed = prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "transactions_failed", - Help: "The accumulated number of failed transactions", - }, - ) -) - -var ( - minResponseTimeMap = sync.Map{} - maxResponseTimeMap = sync.Map{} -) - -// NewPrometheusPusherOutput returns a PrometheusPusherOutput. -func NewPrometheusPusherOutput(gatewayURL, jobName string, mode string) *PrometheusPusherOutput { - return &PrometheusPusherOutput{ - pusher: push.New(gatewayURL, jobName). - Grouping("instance", uuid.NewV1().String()). - Grouping("mode", mode), - } -} - -// PrometheusPusherOutput pushes boomer stats to Prometheus Pushgateway. -type PrometheusPusherOutput struct { - pusher *push.Pusher // Prometheus Pushgateway Pusher -} - -// OnStart will register all prometheus metric collectors -func (o *PrometheusPusherOutput) OnStart() { - // reset all prometheus metrics - resetPrometheusMetrics() - log.Info().Msg("register prometheus metric collectors") - registry := prometheus.NewRegistry() - registry.MustRegister( - // gauge vectors for requests - gaugeNumRequests, - gaugeNumFailures, - gaugeMedianResponseTime, - gaugeAverageResponseTime, - gaugeMinResponseTime, - gaugeMaxResponseTime, - gaugeAverageContentLength, - gaugeCurrentRPS, - gaugeCurrentFailPerSec, - // counter for total - counterErrors, - counterTotalNumRequests, - counterTotalNumFailures, - // summary for total - summaryResponseTime, - // gauges for total - gaugeUsers, - gaugeState, - gaugeDuration, - gaugeTotalAverageResponseTime, - gaugeTotalMinResponseTime, - gaugeTotalMaxResponseTime, - gaugeTotalRPS, - gaugeTotalFailRatio, - gaugeTotalFailPerSec, - gaugeTransactionsPassed, - gaugeTransactionsFailed, - ) - o.pusher = o.pusher.Gatherer(registry) -} - -// OnStop of PrometheusPusherOutput has nothing to do. -func (o *PrometheusPusherOutput) OnStop() { - // update runner state: stopped - gaugeState.Set(float64(StateStopped)) - if err := o.pusher.Push(); err != nil { - log.Error().Err(err).Msg("push to Pushgateway failed") - } -} - -// OnEvent will push metric to Prometheus Pushgataway -func (o *PrometheusPusherOutput) OnEvent(data map[string]interface{}) { - output, err := convertData(data) - if err != nil { - log.Error().Err(err).Msg("failed to convert data") - return - } - - // user count - gaugeUsers.Set(float64(output.UserCount)) - - // runner state - gaugeState.Set(float64(output.State)) - - // min/avg/max response time in total - gaugeTotalAverageResponseTime.Set(output.TotalAvgResponseTime) - gaugeTotalMinResponseTime.WithLabelValues("", "Total").Set(output.TotalMinResponseTime) - gaugeTotalMaxResponseTime.WithLabelValues("", "Total").Set(output.TotalMaxResponseTime) - - // duration - gaugeDuration.Set(output.Duration) - - // rps in total - gaugeTotalRPS.Set(output.TotalRPS) - - // failure ratio in total - gaugeTotalFailRatio.Set(output.TotalFailRatio) - - // failure per second in total - gaugeTotalFailPerSec.Set(output.TotalFailPerSec) - - // accumulated number of transactions - gaugeTransactionsPassed.Set(float64(output.TransactionsPassed)) - gaugeTransactionsFailed.Set(float64(output.TransactionsFailed)) - - for _, stat := range output.Stats { - method := stat.Method - name := stat.Name - // stats in stats interval - gaugeNumRequests.WithLabelValues(method, name).Set(float64(stat.NumRequests)) - gaugeNumFailures.WithLabelValues(method, name).Set(float64(stat.NumFailures)) - gaugeMedianResponseTime.WithLabelValues(method, name).Set(float64(stat.medianResponseTime)) - gaugeAverageResponseTime.WithLabelValues(method, name).Set(float64(stat.avgResponseTime)) - gaugeMinResponseTime.WithLabelValues(method, name).Set(float64(stat.MinResponseTime)) - gaugeMaxResponseTime.WithLabelValues(method, name).Set(float64(stat.MaxResponseTime)) - gaugeAverageContentLength.WithLabelValues(method, name).Set(float64(stat.avgContentLength)) - gaugeCurrentRPS.WithLabelValues(method, name).Set(stat.currentRps) - gaugeCurrentFailPerSec.WithLabelValues(method, name).Set(stat.currentFailPerSec) - for responseTime, count := range stat.ResponseTimes { - var i int64 - for i = 0; i < count; i++ { - summaryResponseTime.WithLabelValues(method, name).Observe(float64(responseTime)) - } - } - // every stat in total - key := fmt.Sprintf("%v_%v", method, name) - minResponseTime, loaded := minResponseTimeMap.LoadOrStore(key, float64(stat.MinResponseTime)) - if loaded { - minResponseTime = math.Min(minResponseTime.(float64), float64(stat.MinResponseTime)) - minResponseTimeMap.Store(key, minResponseTime) - } - gaugeTotalMinResponseTime.WithLabelValues(method, name).Set(minResponseTime.(float64)) - - maxResponseTime, loaded := maxResponseTimeMap.LoadOrStore(key, float64(stat.MaxResponseTime)) - if loaded { - maxResponseTime = math.Max(maxResponseTime.(float64), float64(stat.MaxResponseTime)) - maxResponseTimeMap.Store(key, maxResponseTime) - } - gaugeTotalMaxResponseTime.WithLabelValues(method, name).Set(maxResponseTime.(float64)) - - counterTotalNumRequests.WithLabelValues(method, name).Add(float64(stat.NumRequests)) - counterTotalNumFailures.WithLabelValues(method, name).Add(float64(stat.NumFailures)) - } - - // errors - for _, requestError := range output.Errors { - counterErrors.WithLabelValues( - requestError["method"].(string), - requestError["name"].(string), - requestError["error"].(string), - ).Add(float64(requestError["occurrences"].(int64))) - } - - if err := o.pusher.Push(); err != nil { - log.Error().Err(err).Msg("push to Pushgateway failed") - } -} - -// resetPrometheusMetrics will reset all metrics -func resetPrometheusMetrics() { - log.Info().Msg("reset all prometheus metrics") - gaugeNumRequests.Reset() - gaugeNumFailures.Reset() - gaugeMedianResponseTime.Reset() - gaugeAverageResponseTime.Reset() - gaugeMinResponseTime.Reset() - gaugeMaxResponseTime.Reset() - gaugeAverageContentLength.Reset() - gaugeCurrentRPS.Reset() - gaugeCurrentFailPerSec.Reset() - // counter for total - counterErrors.Reset() - counterTotalNumRequests.Reset() - counterTotalNumFailures.Reset() - // summary for total - summaryResponseTime.Reset() - // gauges for total - gaugeUsers.Set(0) - gaugeState.Set(1) - gaugeDuration.Set(0) - gaugeTotalAverageResponseTime.Set(0) - gaugeTotalMinResponseTime.Reset() - gaugeTotalMaxResponseTime.Reset() - gaugeTotalRPS.Set(0) - gaugeTotalFailRatio.Set(0) - gaugeTotalFailPerSec.Set(0) - gaugeTransactionsPassed.Set(0) - gaugeTransactionsFailed.Set(0) - - minResponseTimeMap = sync.Map{} - maxResponseTimeMap = sync.Map{} -} diff --git a/hrp/pkg/boomer/output_test.go b/hrp/pkg/boomer/output_test.go deleted file mode 100644 index 7a9d3c76..00000000 --- a/hrp/pkg/boomer/output_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package boomer - -import ( - "fmt" - "math" - "testing" -) - -func TestGetMedianResponseTime(t *testing.T) { - numRequests := int64(10) - responseTimes := map[int64]int64{ - 100: 1, - 200: 3, - 300: 6, - } - - medianResponseTime := getMedianResponseTime(numRequests, responseTimes) - if medianResponseTime != 300 { - t.Error("medianResponseTime should be 300") - } - - responseTimes = map[int64]int64{} - - medianResponseTime = getMedianResponseTime(numRequests, responseTimes) - if medianResponseTime != 0 { - t.Error("medianResponseTime should be 0") - } -} - -func TestGetAvgResponseTime(t *testing.T) { - numRequests := int64(3) - totalResponseTime := int64(100) - - avgResponseTime := getAvgResponseTime(numRequests, totalResponseTime) - if math.Dim(float64(33.33), avgResponseTime) > 0.01 { - t.Error("avgResponseTime should be close to 33.33") - } - - avgResponseTime = getAvgResponseTime(int64(0), totalResponseTime) - if avgResponseTime != float64(0) { - t.Error("avgResponseTime should be close to 0") - } -} - -func TestGetAvgContentLength(t *testing.T) { - numRequests := int64(3) - totalContentLength := int64(100) - - avgContentLength := getAvgContentLength(numRequests, totalContentLength) - if avgContentLength != 33 { - t.Error("avgContentLength should be 33") - } - - avgContentLength = getAvgContentLength(int64(0), totalContentLength) - if avgContentLength != 0 { - t.Error("avgContentLength should be 0") - } -} - -func TestGetCurrentRps(t *testing.T) { - duration := float64(3) - numRequests := int64(6) - currentRps := getCurrentRps(numRequests, duration) - if currentRps != 2 { - t.Error("currentRps should be 2") - } - - numRequests = int64(8) - currentRps = getCurrentRps(numRequests, duration) - if fmt.Sprintf("%.2f", currentRps) != "2.67" { - t.Error("currentRps should be 2.67") - } -} - -func TestConsoleOutput(t *testing.T) { - o := NewConsoleOutput() - o.OnStart() - - data := map[string]interface{}{} - stat := map[string]interface{}{} - data["stats"] = []interface{}{stat} - - stat["name"] = "http" - stat["method"] = "POST" - stat["num_requests"] = int64(100) - stat["num_failures"] = int64(10) - stat["response_times"] = map[int64]int64{ - 10: 1, - 100: 99, - } - stat["total_response_time"] = int64(9910) - stat["min_response_time"] = int64(10) - stat["max_response_time"] = int64(100) - stat["total_content_length"] = int64(100000) - stat["num_reqs_per_sec"] = map[int64]int64{ - 1: 20, - 2: 40, - 3: 40, - } - - o.OnEvent(data) - - o.OnStop() -} diff --git a/hrp/pkg/boomer/ratelimiter.go b/hrp/pkg/boomer/ratelimiter.go deleted file mode 100644 index d131c4d5..00000000 --- a/hrp/pkg/boomer/ratelimiter.go +++ /dev/null @@ -1,230 +0,0 @@ -package boomer - -import ( - "errors" - "math" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" -) - -// RateLimiter is used to put limits on task executions. -type RateLimiter interface { - // Start is used to enable the rate limiter. - // It can be implemented as a noop if not needed. - Start() - - // Acquire() is called before executing a task.Fn function. - // If Acquire() returns true, the task.Fn function will be executed. - // If Acquire() returns false, the task.Fn function won't be executed this time, but Acquire() will be called very soon. - // It works like: - // for { - // blocked := rateLimiter.Acquire() - // if !blocked { - // task.Fn() - // } - // } - // Acquire() should block the caller until execution is allowed. - Acquire() bool - - // Stop is used to disable the rate limiter. - // It can be implemented as a noop if not needed. - Stop() -} - -// A StableRateLimiter uses the token bucket algorithm. -// the bucket is refilled according to the refill period, no burst is allowed. -type StableRateLimiter struct { - threshold int64 - currentThreshold int64 - refillPeriod time.Duration - broadcastChanMux *sync.RWMutex // avoid data race - broadcastChannel chan bool - quitChannel chan bool -} - -// NewStableRateLimiter returns a StableRateLimiter. -func NewStableRateLimiter(threshold int64, refillPeriod time.Duration) (rateLimiter *StableRateLimiter) { - rateLimiter = &StableRateLimiter{ - threshold: threshold, - currentThreshold: threshold, - refillPeriod: refillPeriod, - broadcastChanMux: new(sync.RWMutex), - broadcastChannel: make(chan bool), - } - return rateLimiter -} - -// Start to refill the bucket periodically. -func (limiter *StableRateLimiter) Start() { - limiter.quitChannel = make(chan bool) - quitChannel := limiter.quitChannel - go func() { - for { - select { - case <-quitChannel: - return - default: - atomic.StoreInt64(&limiter.currentThreshold, limiter.threshold) - time.Sleep(limiter.refillPeriod) - close(limiter.broadcastChannel) - // avoid data race - limiter.broadcastChanMux.Lock() - limiter.broadcastChannel = make(chan bool) - limiter.broadcastChanMux.Unlock() - } - } - }() -} - -// Acquire a token from the bucket, returns true if the bucket is exhausted. -func (limiter *StableRateLimiter) Acquire() (blocked bool) { - permit := atomic.AddInt64(&limiter.currentThreshold, -1) - if permit < 0 { - blocked = true - // block until the bucket is refilled - limiter.broadcastChanMux.Lock() - <-limiter.broadcastChannel - limiter.broadcastChanMux.Unlock() - } else { - blocked = false - } - return blocked -} - -// Stop the rate limiter. -func (limiter *StableRateLimiter) Stop() { - close(limiter.quitChannel) -} - -// ErrParsingRampUpRate is the error returned if the format of rampUpRate is invalid. -var ErrParsingRampUpRate = errors.New("ratelimiter: invalid format of rampUpRate, try \"1\" or \"1/1s\"") - -// A RampUpRateLimiter uses the token bucket algorithm. -// the threshold is updated according to the warm up rate. -// the bucket is refilled according to the refill period, no burst is allowed. -type RampUpRateLimiter struct { - maxThreshold int64 - nextThreshold int64 - currentThreshold int64 - refillPeriod time.Duration - rampUpRate string - rampUpStep int64 - rampUpPeroid time.Duration - - broadcastChanMux *sync.RWMutex // avoid data race - broadcastChannel chan bool - - rampUpChannel chan bool - quitChannel chan bool -} - -// NewRampUpRateLimiter returns a RampUpRateLimiter. -// Valid formats of rampUpRate are "1", "1/1s". -func NewRampUpRateLimiter(maxThreshold int64, rampUpRate string, refillPeriod time.Duration) (rateLimiter *RampUpRateLimiter, err error) { - rateLimiter = &RampUpRateLimiter{ - maxThreshold: maxThreshold, - nextThreshold: 0, - currentThreshold: 0, - rampUpRate: rampUpRate, - refillPeriod: refillPeriod, - broadcastChanMux: new(sync.RWMutex), - broadcastChannel: make(chan bool), - } - rateLimiter.rampUpStep, rateLimiter.rampUpPeroid, err = rateLimiter.parseRampUpRate(rateLimiter.rampUpRate) - if err != nil { - return nil, err - } - return rateLimiter, nil -} - -func (limiter *RampUpRateLimiter) parseRampUpRate(rampUpRate string) (rampUpStep int64, rampUpPeroid time.Duration, err error) { - if strings.Contains(rampUpRate, "/") { - tmp := strings.Split(rampUpRate, "/") - if len(tmp) != 2 { - return rampUpStep, rampUpPeroid, ErrParsingRampUpRate - } - rampUpStep, err := strconv.ParseInt(tmp[0], 10, 64) - if err != nil { - return rampUpStep, rampUpPeroid, ErrParsingRampUpRate - } - rampUpPeroid, err := time.ParseDuration(tmp[1]) - if err != nil { - return rampUpStep, rampUpPeroid, ErrParsingRampUpRate - } - return rampUpStep, rampUpPeroid, nil - } - - rampUpStep, err = strconv.ParseInt(rampUpRate, 10, 64) - if err != nil { - return rampUpStep, rampUpPeroid, ErrParsingRampUpRate - } - rampUpPeroid = time.Second - return rampUpStep, rampUpPeroid, nil -} - -// Start to refill the bucket periodically. -func (limiter *RampUpRateLimiter) Start() { - limiter.quitChannel = make(chan bool) - quitChannel := limiter.quitChannel - // bucket updater - go func() { - for { - select { - case <-quitChannel: - return - default: - atomic.StoreInt64(&limiter.currentThreshold, atomic.LoadInt64(&limiter.nextThreshold)) - time.Sleep(limiter.refillPeriod) - close(limiter.broadcastChannel) - // avoid data race - limiter.broadcastChanMux.Lock() - limiter.broadcastChannel = make(chan bool) - limiter.broadcastChanMux.Unlock() - } - } - }() - // threshold updater - go func() { - for { - select { - case <-quitChannel: - return - default: - nextValue := atomic.LoadInt64(&limiter.nextThreshold) + limiter.rampUpStep - if nextValue < 0 { - // int64 overflow - nextValue = int64(math.MaxInt64) - } - if nextValue > limiter.maxThreshold { - nextValue = limiter.maxThreshold - } - atomic.StoreInt64(&limiter.nextThreshold, nextValue) - time.Sleep(limiter.rampUpPeroid) - } - } - }() -} - -// Acquire a token from the bucket, returns true if the bucket is exhausted. -func (limiter *RampUpRateLimiter) Acquire() (blocked bool) { - permit := atomic.AddInt64(&limiter.currentThreshold, -1) - if permit < 0 { - blocked = true - // block until the bucket is refilled - limiter.broadcastChanMux.Lock() - <-limiter.broadcastChannel - limiter.broadcastChanMux.Unlock() - } else { - blocked = false - } - return blocked -} - -// Stop the rate limiter. -func (limiter *RampUpRateLimiter) Stop() { - atomic.StoreInt64(&limiter.nextThreshold, 0) - close(limiter.quitChannel) -} diff --git a/hrp/pkg/boomer/ratelimiter_test.go b/hrp/pkg/boomer/ratelimiter_test.go deleted file mode 100644 index eca839d5..00000000 --- a/hrp/pkg/boomer/ratelimiter_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package boomer - -import ( - "testing" - "time" -) - -func TestStableRateLimiter(t *testing.T) { - rateLimiter := NewStableRateLimiter(1, 10*time.Millisecond) - rateLimiter.Start() - defer rateLimiter.Stop() - - blocked := rateLimiter.Acquire() - if blocked { - t.Error("Unexpected blocked by rate limiter") - } - blocked = rateLimiter.Acquire() - if !blocked { - t.Error("Should be blocked") - } -} - -// FIXME -// func TestRampUpRateLimiter(t *testing.T) { -// rateLimiter, _ := NewRampUpRateLimiter(100, "10/200ms", 100*time.Millisecond) -// rateLimiter.Start() -// defer rateLimiter.Stop() - -// time.Sleep(150 * time.Millisecond) - -// for i := 0; i < 10; i++ { -// blocked := rateLimiter.Acquire() -// if blocked { -// t.Fatal("Unexpected blocked by rate limiter") -// } -// } -// blocked := rateLimiter.Acquire() -// if !blocked { -// t.Fatal("Should be blocked") -// } - -// time.Sleep(150 * time.Millisecond) - -// // now, the threshold is 20 -// for i := 0; i < 20; i++ { -// blocked := rateLimiter.Acquire() -// if blocked { -// t.Fatal("Unexpected blocked by rate limiter") -// } -// } -// blocked = rateLimiter.Acquire() -// if !blocked { -// t.Fatal("Should be blocked") -// } -// } - -func TestParseRampUpRate(t *testing.T) { - rateLimiter := &RampUpRateLimiter{} - rampUpStep, rampUpPeriod, _ := rateLimiter.parseRampUpRate("100") - if rampUpStep != 100 { - t.Error("Wrong rampUpStep, expected: 100, was:", rampUpStep) - } - if rampUpPeriod != time.Second { - t.Error("Wrong rampUpPeriod, expected: 1s, was:", rampUpPeriod) - } - rampUpStep, rampUpPeriod, _ = rateLimiter.parseRampUpRate("200/10s") - if rampUpStep != 200 { - t.Error("Wrong rampUpStep, expected: 200, was:", rampUpStep) - } - if rampUpPeriod != 10*time.Second { - t.Error("Wrong rampUpPeriod, expected: 10s, was:", rampUpPeriod) - } -} - -func TestParseInvalidRampUpRate(t *testing.T) { - rateLimiter := &RampUpRateLimiter{} - - _, _, err := rateLimiter.parseRampUpRate("A/1m") - if err == nil || err != ErrParsingRampUpRate { - t.Error("Expected ErrParsingRampUpRate") - } - - _, _, err = rateLimiter.parseRampUpRate("A") - if err == nil || err != ErrParsingRampUpRate { - t.Error("Expected ErrParsingRampUpRate") - } - - _, _, err = rateLimiter.parseRampUpRate("200/1s/") - if err == nil || err != ErrParsingRampUpRate { - t.Error("Expected ErrParsingRampUpRate") - } - - _, _, err = rateLimiter.parseRampUpRate("200/1") - if err == nil || err != ErrParsingRampUpRate { - t.Error("Expected ErrParsingRampUpRate") - } - - rateLimiter, err = NewRampUpRateLimiter(1, "200/1", time.Second) - if err == nil || err != ErrParsingRampUpRate { - t.Error("Expected ErrParsingRampUpRate") - } -} diff --git a/hrp/pkg/boomer/runner.go b/hrp/pkg/boomer/runner.go deleted file mode 100644 index d9e5d5f4..00000000 --- a/hrp/pkg/boomer/runner.go +++ /dev/null @@ -1,1417 +0,0 @@ -package boomer - -import ( - "fmt" - "math/rand" - "os" - "runtime/debug" - "strconv" - "sync" - "sync/atomic" - "time" - - "github.com/jinzhu/copier" - "github.com/olekukonko/tablewriter" - "github.com/pkg/errors" - "github.com/rs/zerolog/log" - - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/grpc/messager" -) - -const ( - StateInit = iota + 1 // initializing - StateSpawning // spawning - StateRunning // running - StateStopping // stopping - StateStopped // stopped - StateQuitting // quitting - StateMissing // missing -) - -func getStateName(state int32) (stateName string) { - switch state { - case StateInit: - stateName = "initializing" - case StateSpawning: - stateName = "spawning" - case StateRunning: - stateName = "running" - case StateStopping: - stateName = "stopping" - case StateStopped: - stateName = "stopped" - case StateQuitting: - stateName = "quitting" - case StateMissing: - stateName = "missing" - } - return -} - -const ( - reportStatsInterval = 3 * time.Second - heartbeatInterval = 1 * time.Second - heartbeatLiveness = 3 * time.Second - stateMachineInterval = 1 * time.Second -) - -type Loop struct { - loopCount int64 // more than 0 - acquiredCount int64 // count acquired of load testing - finishedCount int64 // count finished of load testing -} - -func (l *Loop) isFinished() bool { - // return true when there are no remaining loop count to test - return atomic.LoadInt64(&l.finishedCount) == l.loopCount -} - -func (l *Loop) acquire() bool { - // get one ticket when there are still remaining loop count to test - // return true when getting ticket successfully - if atomic.LoadInt64(&l.acquiredCount) < l.loopCount { - atomic.AddInt64(&l.acquiredCount, 1) - return true - } - return false -} - -func (l *Loop) increaseFinishedCount() { - atomic.AddInt64(&l.finishedCount, 1) -} - -type Controller struct { - mutex sync.RWMutex - once sync.Once - currentClientsNum int64 // current clients count - spawnCount int64 // target clients to spawn - spawnRate float64 - rebalance chan bool // dynamically balance boomer running parameters - spawnDone chan struct{} - tasks []*Task -} - -func (c *Controller) setSpawn(spawnCount int64, spawnRate float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - if spawnCount > 0 { - atomic.StoreInt64(&c.spawnCount, spawnCount) - } - if spawnRate > 0 { - c.spawnRate = spawnRate - } -} - -func (c *Controller) setSpawnCount(spawnCount int64) { - if spawnCount > 0 { - atomic.StoreInt64(&c.spawnCount, spawnCount) - } -} - -func (c *Controller) setSpawnRate(spawnRate float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - if spawnRate > 0 { - c.spawnRate = spawnRate - } -} - -func (c *Controller) getSpawnCount() int64 { - c.mutex.RLock() - defer c.mutex.RUnlock() - return atomic.LoadInt64(&c.spawnCount) -} - -func (c *Controller) getSpawnRate() float64 { - c.mutex.RLock() - defer c.mutex.RUnlock() - return c.spawnRate -} - -func (c *Controller) getSpawnDone() chan struct{} { - c.mutex.RLock() - defer c.mutex.RUnlock() - return c.spawnDone -} - -func (c *Controller) getCurrentClientsNum() int64 { - c.mutex.RLock() - defer c.mutex.RUnlock() - return atomic.LoadInt64(&c.currentClientsNum) -} - -func (c *Controller) spawnCompete() { - close(c.spawnDone) -} - -func (c *Controller) getRebalanceChan() chan bool { - c.mutex.RLock() - defer c.mutex.RUnlock() - return c.rebalance -} - -func (c *Controller) isFinished() bool { - // return true when workers acquired - return atomic.LoadInt64(&c.currentClientsNum) == atomic.LoadInt64(&c.spawnCount) -} - -func (c *Controller) acquire() bool { - // get one ticket when there are still remaining spawn count to test - // return true when getting ticket successfully - if atomic.LoadInt64(&c.currentClientsNum) < atomic.LoadInt64(&c.spawnCount) { - atomic.AddInt64(&c.currentClientsNum, 1) - return true - } - return false -} - -func (c *Controller) erase() bool { - // return true if acquiredCount > spawnCount - if atomic.LoadInt64(&c.currentClientsNum) > atomic.LoadInt64(&c.spawnCount) { - atomic.AddInt64(&c.currentClientsNum, -1) - return true - } - return false -} - -func (c *Controller) increaseFinishedCount() { - atomic.AddInt64(&c.currentClientsNum, -1) -} - -func (c *Controller) reset() { - c.mutex.Lock() - defer c.mutex.Unlock() - atomic.StoreInt64(&c.spawnCount, 0) - c.spawnRate = 0 - atomic.StoreInt64(&c.currentClientsNum, 0) - c.spawnDone = make(chan struct{}) - c.rebalance = make(chan bool) - c.tasks = []*Task{} - c.once = sync.Once{} -} - -type runner struct { - state int32 - - tasks []*Task - totalTaskWeight int - mutex sync.RWMutex - - rateLimiter RateLimiter - rateLimitEnabled bool - stats *requestStats - - spawnCount int64 // target clients to spawn - spawnRate float64 - runTime int64 - - controller *Controller - loop *Loop // specify loop count for testcase, count = loopCount * spawnCount - - // stop signals the run goroutine should shutdown. - stopChan chan bool - // all running workers(goroutines) will select on this channel. - // stopping is closed by run goroutine on shutdown. - stoppingChan chan bool - // done is closed when all goroutines from start() complete. - doneChan chan bool - // when this channel is closed, all statistics are reported successfully - reportedChan chan bool - - // close this channel will stop all goroutines used in runner. - closeChan chan bool - - // wgMu blocks concurrent waitgroup mutation while boomer stopping - wgMu sync.RWMutex - // wg is used to wait for all running workers(goroutines) that depends on the boomer state - // to exit when stopping the boomer. - wg sync.WaitGroup - - outputs []Output -} - -func (r *runner) setSpawnRate(spawnRate float64) { - r.mutex.Lock() - defer r.mutex.Unlock() - if spawnRate > 0 { - r.spawnRate = spawnRate - } -} - -func (r *runner) getSpawnRate() float64 { - r.mutex.RLock() - defer r.mutex.RUnlock() - return r.spawnRate -} - -func (r *runner) setRunTime(runTime int64) { - atomic.StoreInt64(&r.runTime, runTime) -} - -func (r *runner) getRunTime() int64 { - return atomic.LoadInt64(&r.runTime) -} - -func (r *runner) getSpawnCount() int64 { - return atomic.LoadInt64(&r.spawnCount) -} - -func (r *runner) setSpawnCount(spawnCount int64) { - atomic.StoreInt64(&r.spawnCount, spawnCount) -} - -// safeRun runs fn and recovers from unexpected panics. -// it prevents panics from Task.Fn crashing boomer. -func (r *runner) safeRun(fn func()) { - defer func() { - // don't panic - err := recover() - if err != nil { - stackTrace := debug.Stack() - errMsg := fmt.Sprintf("%v", err) - os.Stderr.Write([]byte(errMsg)) - os.Stderr.Write([]byte("\n")) - os.Stderr.Write(stackTrace) - } - }() - fn() -} - -func (r *runner) addOutput(o Output) { - r.outputs = append(r.outputs, o) -} - -func (r *runner) outputOnStart() { - size := len(r.outputs) - if size == 0 { - return - } - wg := sync.WaitGroup{} - wg.Add(size) - for _, output := range r.outputs { - go func(o Output) { - o.OnStart() - wg.Done() - }(output) - } - wg.Wait() -} - -func (r *runner) outputOnEvent(data map[string]interface{}) { - size := len(r.outputs) - if size == 0 { - return - } - wg := sync.WaitGroup{} - wg.Add(size) - for _, output := range r.outputs { - go func(o Output) { - o.OnEvent(data) - wg.Done() - }(output) - } - wg.Wait() -} - -func (r *runner) outputOnStop() { - defer func() { - r.outputs = make([]Output, 0) - }() - size := len(r.outputs) - if size == 0 { - return - } - wg := sync.WaitGroup{} - wg.Add(size) - for _, output := range r.outputs { - go func(o Output) { - o.OnStop() - wg.Done() - }(output) - } - wg.Wait() -} - -func (r *runner) reportStats() { - data := r.stats.collectReportData() - data["user_count"] = r.controller.getCurrentClientsNum() - data["state"] = atomic.LoadInt32(&r.state) - r.outputOnEvent(data) -} - -func (r *runner) reportTestResult() { - // convert stats in total - var statsTotal interface{} = r.stats.total.serialize() - entryTotalOutput, err := deserializeStatsEntry(statsTotal) - if err != nil { - return - } - duration := time.Duration(entryTotalOutput.LastRequestTimestamp-entryTotalOutput.StartTime) * time.Millisecond - currentTime := time.Now() - println(fmt.Sprint("=========================================== Statistics Summary ==========================================")) - println(fmt.Sprintf("Current time: %s, Users: %v, Duration: %v, Accumulated Transactions: %d Passed, %d Failed", - currentTime.Format("2006/01/02 15:04:05"), r.controller.getCurrentClientsNum(), duration, r.stats.transactionPassed, r.stats.transactionFailed)) - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Name", "# requests", "# fails", "Median", "Average", "Min", "Max", "Content Size", "# reqs/sec", "# fails/sec"}) - row := make([]string, 10) - row[0] = entryTotalOutput.Name - row[1] = strconv.FormatInt(entryTotalOutput.NumRequests, 10) - row[2] = strconv.FormatInt(entryTotalOutput.NumFailures, 10) - row[3] = strconv.FormatInt(entryTotalOutput.medianResponseTime, 10) - row[4] = strconv.FormatFloat(entryTotalOutput.avgResponseTime, 'f', 2, 64) - row[5] = strconv.FormatInt(entryTotalOutput.MinResponseTime, 10) - row[6] = strconv.FormatInt(entryTotalOutput.MaxResponseTime, 10) - row[7] = strconv.FormatInt(entryTotalOutput.avgContentLength, 10) - row[8] = strconv.FormatFloat(entryTotalOutput.currentRps, 'f', 2, 64) - row[9] = strconv.FormatFloat(entryTotalOutput.currentFailPerSec, 'f', 2, 64) - table.Append(row) - table.Render() - println() -} - -func (r *runner) reset() { - r.controller.reset() - r.stats.clearAll() - r.stoppingChan = make(chan bool) - r.doneChan = make(chan bool) - r.reportedChan = make(chan bool) -} - -func (r *runner) runTimeCheck(runTime int64) { - if runTime <= 0 { - return - } - stopTime := time.Now().Unix() + runTime - - ticker := time.NewTicker(time.Second) - for { - select { - case <-r.stopChan: - return - case <-ticker.C: - if time.Now().Unix() > stopTime { - r.stop() - return - } - } - } -} - -func (r *runner) spawnWorkers(spawnCount int64, spawnRate float64, quit chan bool, spawnCompleteFunc func()) { - r.updateState(StateSpawning) - log.Info(). - Int64("spawnCount", spawnCount). - Float64("spawnRate", spawnRate). - Msg("Spawning workers") - - r.controller.setSpawn(spawnCount, spawnRate) - - for { - select { - case <-quit: - // quit spawning goroutine - log.Info().Msg("Quitting spawning workers") - return - default: - if r.isStarting() && r.controller.acquire() { - // spawn workers with rate limit - sleepTime := time.Duration(1000000/r.controller.getSpawnRate()) * time.Microsecond - time.Sleep(sleepTime) - // loop count per worker - var workerLoop *Loop - if r.loop != nil { - workerLoop = &Loop{loopCount: atomic.LoadInt64(&r.loop.loopCount) / r.controller.spawnCount} - } - r.goAttach(func() { - for { - select { - case <-quit: - r.controller.increaseFinishedCount() - return - default: - if workerLoop != nil && !workerLoop.acquire() { - r.controller.increaseFinishedCount() - return - } - if r.rateLimitEnabled { - blocked := r.rateLimiter.Acquire() - if !blocked { - task := r.getTask() - r.safeRun(task.Fn) - } - } else { - task := r.getTask() - r.safeRun(task.Fn) - } - if workerLoop != nil { - // finished count of total - r.loop.increaseFinishedCount() - // finished count of single worker - workerLoop.increaseFinishedCount() - if r.loop.isFinished() { - go r.stop() - r.controller.increaseFinishedCount() - return - } - } - if r.controller.erase() { - return - } - } - } - }) - continue - } - - r.controller.once.Do( - func() { - // spawning compete - r.controller.spawnCompete() - if spawnCompleteFunc != nil { - spawnCompleteFunc() - } - r.updateState(StateRunning) - }, - ) - - <-r.controller.getRebalanceChan() - if r.isStarting() { - // rebalance spawn count - r.controller.setSpawn(r.getSpawnCount(), r.getSpawnRate()) - } - } - } -} - -// goAttach creates a goroutine on a given function and tracks it using -// the runner waitgroup. -// The passed function should interrupt on r.stoppingNotify(). -func (r *runner) goAttach(f func()) { - r.wgMu.RLock() // this blocks with ongoing close(s.stopping) - defer r.wgMu.RUnlock() - select { - case <-r.stoppingChan: - log.Warn().Msg("runner has stopped; skipping GoAttach") - return - default: - } - - // now safe to add since waitgroup wait has not started yet - r.wg.Add(1) - go func() { - defer r.wg.Done() - f() - }() -} - -// setTasks will set the runner's task list AND the total task weight -// which is used to get a random task later -func (r *runner) setTasks(t []*Task) { - r.mutex.Lock() - defer r.mutex.Unlock() - r.tasks = t - - weightSum := 0 - for _, task := range r.tasks { - weightSum += task.Weight - } - r.totalTaskWeight = weightSum -} - -func (r *runner) getTask() *Task { - r.mutex.RLock() - defer r.mutex.RUnlock() - tasksCount := len(r.tasks) - if tasksCount == 0 { - log.Error().Msg("no valid testcase found") - os.Exit(1) - } else if tasksCount == 1 { - // Fast path - return r.tasks[0] - } - - rs := rand.New(rand.NewSource(time.Now().UnixNano())) - - totalWeight := r.totalTaskWeight - if totalWeight <= 0 { - // If all the tasks have not weights defined, they have the same chance to run - randNum := rs.Intn(tasksCount) - return r.tasks[randNum] - } - - randNum := rs.Intn(totalWeight) - runningSum := 0 - for _, task := range r.tasks { - runningSum += task.Weight - if runningSum > randNum { - return task - } - } - - return nil -} - -func (r *runner) statsStart() { - ticker := time.NewTicker(reportStatsInterval) - for { - select { - // record stats - case t := <-r.stats.transactionChan: - r.stats.logTransaction(t.name, t.success, t.elapsedTime, t.contentSize) - case m := <-r.stats.requestSuccessChan: - r.stats.logRequest(m.requestType, m.name, m.responseTime, m.responseLength) - case n := <-r.stats.requestFailureChan: - r.stats.logRequest(n.requestType, n.name, n.responseTime, 0) - r.stats.logError(n.requestType, n.name, n.errMsg) - // report stats - case <-ticker.C: - r.reportStats() - // close reportedChan and return if the last stats is reported successfully - if !r.isStarting() && !r.isStopping() { - close(r.reportedChan) - log.Info().Msg("Quitting statsStart") - return - } - } - } -} - -func (r *runner) stop() { - // stop previous goroutines without blocking - // those goroutines will exit when r.safeRun returns - r.gracefulStop() - if r.rateLimitEnabled { - r.rateLimiter.Stop() - } - r.updateState(StateStopped) -} - -// gracefulStop stops the boomer gracefully, and shuts down the running goroutine. -// gracefulStop should be called after a start(), otherwise it will block forever. -// When stopping leader, Stop transfers its leadership to one of its peers -// before stopping the boomer. -// gracefulStop terminates the boomer and performs any necessary finalization. -// Do and Process cannot be called after Stop has been invoked. -func (r *runner) gracefulStop() { - select { - case r.stopChan <- true: - case <-r.doneChan: - return - } - <-r.doneChan -} - -// stopNotify returns a channel that receives a bool type value -// when the runner is stopped. -func (r *runner) stopNotify() <-chan bool { return r.doneChan } - -func (r *runner) getState() int32 { - return atomic.LoadInt32(&r.state) -} - -func (r *runner) updateState(state int32) { - log.Debug().Int32("from", atomic.LoadInt32(&r.state)).Int32("to", state).Msg("update runner state") - atomic.StoreInt32(&r.state, state) -} - -func (r *runner) isStarting() bool { - return r.getState() == StateRunning || r.getState() == StateSpawning -} - -func (r *runner) isStopping() bool { - return r.getState() == StateStopping -} - -type localRunner struct { - runner - - profile *Profile -} - -func newLocalRunner(spawnCount int64, spawnRate float64) *localRunner { - return &localRunner{ - runner: runner{ - state: StateInit, - stats: newRequestStats(), - spawnCount: spawnCount, - spawnRate: spawnRate, - controller: &Controller{}, - outputs: make([]Output, 0), - stopChan: make(chan bool), - closeChan: make(chan bool), - wg: sync.WaitGroup{}, - wgMu: sync.RWMutex{}, - }, - } -} - -func (r *localRunner) start() { - r.updateState(StateInit) - // init localRunner - r.reset() - - // start rate limiter - if r.rateLimitEnabled { - r.rateLimiter.Start() - } - // output setup - r.outputOnStart() - - go r.runTimeCheck(r.getRunTime()) - - go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stoppingChan, nil) - - defer func() { - // block concurrent waitgroup adds in GoAttach while stopping - r.wgMu.Lock() - r.updateState(StateStopping) - close(r.stoppingChan) - close(r.controller.rebalance) - r.wgMu.Unlock() - - // wait for goroutines before closing - r.wg.Wait() - - close(r.doneChan) - - // wait until all stats are reported successfully - <-r.reportedChan - // report test result - r.reportTestResult() - // output teardown - r.outputOnStop() - - r.updateState(StateQuitting) - }() - - // start stats report - go r.statsStart() - - <-r.stopChan -} - -func (r *localRunner) stop() { - if r.runner.isStarting() { - r.runner.stop() - } -} - -// workerRunner connects to the master, spawns goroutines and collects stats. -type workerRunner struct { - runner - - nodeID string - masterHost string - masterPort int - client *grpcClient - - profile *Profile - testCasesBytes []byte - - tasksChan chan *task - - mutex sync.Mutex - ignoreQuit bool -} - -func newWorkerRunner(masterHost string, masterPort int) (r *workerRunner) { - r = &workerRunner{ - runner: runner{ - stats: newRequestStats(), - outputs: make([]Output, 0), - controller: &Controller{}, - stopChan: make(chan bool), - closeChan: make(chan bool), - }, - masterHost: masterHost, - masterPort: masterPort, - nodeID: getNodeID(), - tasksChan: make(chan *task, 10), - mutex: sync.Mutex{}, - ignoreQuit: false, - } - return r -} - -func (r *workerRunner) spawnComplete() { - data := make(map[string][]byte) - data["count"] = builtin.Int64ToBytes(r.controller.getSpawnCount()) - r.client.sendChannel() <- newGenericMessage("spawning_complete", data, r.nodeID) -} - -func (r *workerRunner) onSpawnMessage(msg *genericMessage) { - r.client.sendChannel() <- newGenericMessage("spawning", nil, r.nodeID) - if msg.Profile == nil { - log.Error().Msg("miss profile") - } - profile := BytesToProfile(msg.Profile) - r.setSpawnCount(profile.SpawnCount) - r.setSpawnRate(profile.SpawnRate) - - if msg.Tasks == nil && len(r.tasks) == 0 { - log.Error().Msg("miss tasks") - } - r.tasksChan <- &task{ - Profile: profile, - TestCasesBytes: msg.Tasks, - } - log.Info().Msg("on spawn message successfully") -} - -func (r *workerRunner) onRebalanceMessage(msg *genericMessage) { - if msg.Profile == nil { - log.Error().Msg("miss profile") - } - profile := BytesToProfile(msg.Profile) - r.setSpawnCount(profile.SpawnCount) - r.setSpawnRate(profile.SpawnRate) - - r.tasksChan <- &task{ - Profile: profile, - } - log.Info().Msg("on rebalance message successfully") -} - -// Runner acts as a state machine. -func (r *workerRunner) onMessage(msg *genericMessage) { - switch r.getState() { - case StateInit: - switch msg.Type { - case "spawn": - r.onSpawnMessage(msg) - case "quit": - if r.ignoreQuit { - log.Warn().Msg("master already quit, waiting to reconnect master.") - break - } - r.close() - } - case StateSpawning: - fallthrough - case StateRunning: - switch msg.Type { - case "spawn": - r.onSpawnMessage(msg) - case "rebalance": - r.onRebalanceMessage(msg) - case "stop": - r.stop() - case "quit": - r.stop() - if r.ignoreQuit { - log.Warn().Msg("master already quit, waiting to reconnect master.") - break - } - r.close() - log.Info().Msg("Recv quit message from master, all the goroutines are stopped") - } - case StateStopped: - switch msg.Type { - case "spawn": - r.onSpawnMessage(msg) - case "quit": - if r.ignoreQuit { - log.Warn().Msg("master already quit, waiting to reconnect master.") - break - } - r.close() - } - } -} - -func (r *workerRunner) onStopped() { - r.client.sendChannel() <- newGenericMessage("client_stopped", nil, r.nodeID) -} - -func (r *workerRunner) onQuiting() { - if r.getState() != StateQuitting { - r.client.sendChannel() <- newQuitMessage(r.nodeID) - } - r.updateState(StateQuitting) -} - -func (r *workerRunner) startListener() { - for { - select { - case msg := <-r.client.recvChannel(): - r.onMessage(msg) - case <-r.closeChan: - return - } - } -} - -// run worker service -func (r *workerRunner) run() { - println("==================== HttpRunner Worker for Distributed Load Testing ==================== ") - r.updateState(StateInit) - r.client = newClient(r.masterHost, r.masterPort, r.nodeID) - println(fmt.Sprintf("ready to connect master to %s:%d", r.masterHost, r.masterPort)) - err := r.client.start() - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to connect to master(%s:%d)", r.masterHost, r.masterPort)) - } - - // register worker information to master - if err = r.client.register(r.client.config.ctx); err != nil { - log.Error().Err(err).Msg("failed to register") - } - - err = r.client.newBiStreamClient() - if err != nil { - log.Error().Err(err).Msg("failed to establish bidirectional stream, waiting master launched") - } - - go r.client.recv() - go r.client.send() - - defer func() { - // wait for goroutines before closing - r.wg.Wait() - - // notify master that worker is quitting - r.onQuiting() - - ticker := time.NewTicker(1 * time.Second) - if r.client != nil { - // waitting for quit message is sent to master - select { - case <-r.client.disconnectedChannel(): - case <-ticker.C: - log.Warn().Msg("timeout waiting for sending quit message to master, boomer will quit any way.") - } - - // sign out from master - if err = r.client.signOut(r.client.config.ctx); err != nil { - log.Info().Err(err).Msg("failed to sign out") - } - - // close grpc client - r.client.close() - } - }() - - // listen to master - go r.startListener() - - // tell master, I'm ready - log.Info().Msg("send client ready signal") - r.client.sendChannel() <- newClientReadyMessageToMaster(r.nodeID) - - // heartbeat - // See: https://github.com/locustio/locust/commit/a8c0d7d8c588f3980303358298870f2ea394ab93 - ticker := time.NewTicker(heartbeatInterval) - for { - select { - case <-ticker.C: - if r.getState() == StateMissing { - err = r.client.register(r.client.config.ctx) - if err != nil { - continue - } - err = r.client.newBiStreamClient() - if err != nil { - continue - } - r.updateState(StateInit) - } - if atomic.LoadInt32(&r.client.failCount) > 3 { - go r.stop() - if !r.isStarting() && !r.isStopping() { - r.updateState(StateMissing) - } - continue - } - CPUUsage := GetCurrentCPUPercent() - MemoryUsage := GetCurrentMemoryPercent() - PidCPUUsage := GetCurrentPidCPUUsage() - PidMemoryUsage := GetCurrentPidMemoryUsage() - data := map[string][]byte{ - "state": builtin.Int64ToBytes(int64(r.getState())), - "current_cpu_usage": builtin.Float64ToByte(CPUUsage), - "current_pid_cpu_usage": builtin.Float64ToByte(PidCPUUsage), - "current_memory_usage": builtin.Float64ToByte(MemoryUsage), - "current_pid_memory_usage": builtin.Float64ToByte(PidMemoryUsage), - "current_users": builtin.Int64ToBytes(r.controller.getCurrentClientsNum()), - } - r.client.sendChannel() <- newGenericMessage("heartbeat", data, r.nodeID) - case <-r.closeChan: - return - } - } -} - -func (r *workerRunner) start() { - r.mutex.Lock() - defer r.mutex.Unlock() - r.updateState(StateInit) - r.reset() - - // start rate limiter - if r.rateLimitEnabled { - r.rateLimiter.Start() - } - - r.outputOnStart() - - go r.runTimeCheck(r.getRunTime()) - - go r.spawnWorkers(r.getSpawnCount(), r.getSpawnRate(), r.stoppingChan, r.spawnComplete) - - defer func() { - // block concurrent waitgroup adds in GoAttach while stopping - r.wgMu.Lock() - r.updateState(StateStopping) - close(r.controller.rebalance) - close(r.stoppingChan) - r.wgMu.Unlock() - - // wait for goroutines before closing - r.wg.Wait() - - // reset loop - if r.loop != nil { - r.loop = nil - } - - close(r.doneChan) - - // wait until all stats are reported successfully - <-r.reportedChan - // report test result - r.reportTestResult() - // output teardown - r.outputOnStop() - - // notify master that worker is stopped - r.onStopped() - }() - - // start stats report - go r.statsStart() - - <-r.stopChan -} - -func (r *workerRunner) stop() { - if r.isStarting() { - r.runner.stop() - } -} - -func (r *workerRunner) close() { - close(r.closeChan) -} - -// masterRunner controls worker to spawn goroutines and collect stats. -type masterRunner struct { - runner - - masterBindHost string - masterBindPort int - server *grpcServer - - autoStart bool - expectWorkers int - expectWorkersMaxWait int - - profile *Profile - - parseTestCasesChan chan bool - testCaseBytesChan chan []byte - testCasesBytes []byte -} - -func newMasterRunner(masterBindHost string, masterBindPort int) *masterRunner { - return &masterRunner{ - runner: runner{ - state: StateInit, - stoppingChan: make(chan bool), - doneChan: make(chan bool), - closeChan: make(chan bool), - wg: sync.WaitGroup{}, - wgMu: sync.RWMutex{}, - }, - masterBindHost: masterBindHost, - masterBindPort: masterBindPort, - server: newServer(masterBindHost, masterBindPort), - parseTestCasesChan: make(chan bool), - testCaseBytesChan: make(chan []byte), - } -} - -func (r *masterRunner) setExpectWorkers(expectWorkers int, expectWorkersMaxWait int) { - r.expectWorkers = expectWorkers - r.expectWorkersMaxWait = expectWorkersMaxWait -} - -func (r *masterRunner) heartbeatWorker() { - log.Info().Msg("heartbeatWorker, listen and record heartbeat from worker") - heartBeatTicker := time.NewTicker(heartbeatInterval) - reportTicker := time.NewTicker(heartbeatLiveness) - for { - select { - case <-r.closeChan: - return - case <-heartBeatTicker.C: - r.server.clients.Range(func(key, value interface{}) bool { - workerInfo, ok := value.(*WorkerNode) - if !ok { - log.Error().Msg("failed to get worker information") - } - go func() { - if atomic.LoadInt32(&workerInfo.Heartbeat) < 0 { - if workerInfo.getState() != StateMissing { - workerInfo.setState(StateMissing) - } - } else { - atomic.AddInt32(&workerInfo.Heartbeat, -1) - } - }() - return true - }) - case <-reportTicker.C: - r.reportStats() - } - } -} - -func (r *masterRunner) clientListener() { - log.Info().Msg("clientListener, start to deal message from worker") - for { - select { - case <-r.closeChan: - return - case msg := <-r.server.recvChannel(): - worker, ok := r.server.getClients().Load(msg.NodeID) - if !ok { - continue - } - workerInfo, ok := worker.(*WorkerNode) - if !ok { - continue - } - go func() { - switch msg.Type { - case typeClientReady: - workerInfo.setState(StateInit) - case typeClientStopped: - workerInfo.setState(StateStopped) - case typeHeartbeat: - if workerInfo.getState() == StateMissing { - workerInfo.setState(int32(builtin.BytesToInt64(msg.Data["state"]))) - } - workerInfo.updateHeartbeat(3) - currentCPUUsage, ok := msg.Data["current_cpu_usage"] - if ok { - workerInfo.updateCPUUsage(builtin.ByteToFloat64(currentCPUUsage)) - } - currentPidCpuUsage, ok := msg.Data["current_pid_cpu_usage"] - if ok { - workerInfo.updateWorkerCPUUsage(builtin.ByteToFloat64(currentPidCpuUsage)) - } - currentMemoryUsage, ok := msg.Data["current_memory_usage"] - if ok { - workerInfo.updateMemoryUsage(builtin.ByteToFloat64(currentMemoryUsage)) - } - currentPidMemoryUsage, ok := msg.Data["current_pid_memory_usage"] - if ok { - workerInfo.updateWorkerMemoryUsage(builtin.ByteToFloat64(currentPidMemoryUsage)) - } - currentUsers, ok := msg.Data["current_users"] - if ok { - workerInfo.updateUserCount(builtin.BytesToInt64(currentUsers)) - } - case typeSpawning: - workerInfo.setState(StateSpawning) - case typeSpawningComplete: - workerInfo.setState(StateRunning) - case typeQuit: - if workerInfo.getState() == StateQuitting { - break - } - workerInfo.setState(StateQuitting) - case typeException: - // Todo - default: - } - }() - } - } -} - -func (r *masterRunner) stateMachine() { - ticker := time.NewTicker(stateMachineInterval) - for { - select { - case <-r.closeChan: - return - case <-ticker.C: - switch r.getState() { - case StateSpawning: - if r.server.getCurrentUsers() == int(r.getSpawnCount()) { - log.Warn().Msg("all workers spawn done, setting state as running") - r.updateState(StateRunning) - } - case StateRunning: - if r.server.getStartingClientsLength() == 0 { - r.updateState(StateStopped) - continue - } - if r.server.getWorkersLengthByState(StateInit) != 0 { - err := r.rebalance() - if err != nil { - log.Error().Err(err).Msg("failed to rebalance") - } - } - case StateStopping: - if r.server.getReadyClientsLength() == r.server.getAvailableClientsLength() { - r.updateState(StateStopped) - } - } - - } - } -} - -func (r *masterRunner) run() { - r.updateState(StateInit) - - // start grpc server - err := r.server.start() - if err != nil { - log.Error().Err(err).Msg("failed to start grpc server") - return - } - - defer func() { - // close server - r.server.close() - }() - - if r.autoStart { - go func() { - log.Info().Msg("auto start, waiting expected workers joined") - ticker := time.NewTicker(1 * time.Second) - tickerMaxWait := time.NewTicker(time.Duration(r.expectWorkersMaxWait) * time.Second) - for { - select { - case <-r.closeChan: - return - case <-ticker.C: - c := r.server.getAvailableClientsLength() - log.Info().Msg(fmt.Sprintf("expected worker number: %v, current worker count: %v", r.expectWorkers, c)) - if c >= r.expectWorkers { - err = r.start() - if err != nil { - log.Error().Err(err).Msg("failed to run") - os.Exit(1) - } - return - } - case <-tickerMaxWait.C: - log.Warn().Msg("reached max wait time, quiting") - r.onQuiting() - os.Exit(1) - } - } - }() - } - - // master state machine - r.goAttach(r.stateMachine) - - // listen and deal message from worker - r.goAttach(r.clientListener) - - // listen and record heartbeat from worker - r.heartbeatWorker() - <-r.closeChan -} - -func (r *masterRunner) start() error { - numWorkers := r.server.getAvailableClientsLength() - if numWorkers == 0 { - return errors.New("current available workers: 0") - } - - // fetching testcases - testCasesBytes, err := r.fetchTestCases() - if err != nil { - return err - } - - workerProfile := &Profile{} - if err := copier.Copy(workerProfile, r.profile); err != nil { - log.Error().Err(err).Msg("copy workerProfile failed") - return err - } - - // spawn count - spawnCounts := builtin.SplitInteger(int(r.profile.SpawnCount), numWorkers) - - // spawn rate - spawnRate := workerProfile.SpawnRate / float64(numWorkers) - if spawnRate < 1 { - spawnRate = 1 - } - - // max RPS - maxRPSs := builtin.SplitInteger(int(workerProfile.MaxRPS), numWorkers) - - r.updateState(StateSpawning) - log.Info().Msg("send spawn data to worker") - - cur := 0 - r.server.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing { - return true - } - - if workerProfile.SpawnCount > 0 { - workerProfile.SpawnCount = int64(spawnCounts[cur]) - } - workerProfile.MaxRPS = int64(maxRPSs[cur]) - workerProfile.SpawnRate = spawnRate - - workerInfo.getStream() <- &messager.StreamResponse{ - Type: "spawn", - Profile: ProfileToBytes(workerProfile), - NodeID: workerInfo.ID, - Tasks: testCasesBytes, - } - cur++ - } - return true - }) - - log.Warn().Interface("profile", r.profile).Msg("send spawn data to worker successfully") - return nil -} - -func (r *masterRunner) rebalance() error { - numWorkers := r.server.getAvailableClientsLength() - if numWorkers == 0 { - return errors.New("current available workers: 0") - } - workerProfile := &Profile{} - if err := copier.Copy(workerProfile, r.profile); err != nil { - log.Error().Err(err).Msg("copy workerProfile failed") - return err - } - - // spawn count - spawnCounts := builtin.SplitInteger(int(r.profile.SpawnCount), numWorkers) - - // spawn rate - spawnRate := workerProfile.SpawnRate / float64(numWorkers) - if spawnRate < 1 { - spawnRate = 1 - } - - // max RPS - maxRPSs := builtin.SplitInteger(int(workerProfile.MaxRPS), numWorkers) - - cur := 0 - log.Info().Msg("send spawn data to worker") - r.server.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.getState() == StateQuitting || workerInfo.getState() == StateMissing { - return true - } - - if workerProfile.SpawnCount > 0 { - workerProfile.SpawnCount = int64(spawnCounts[cur]) - } - workerProfile.MaxRPS = int64(maxRPSs[cur]) - workerProfile.SpawnRate = spawnRate - - if workerInfo.getState() == StateInit { - workerInfo.getStream() <- &messager.StreamResponse{ - Type: "spawn", - Profile: ProfileToBytes(workerProfile), - NodeID: workerInfo.ID, - Tasks: r.testCasesBytes, - } - } else { - workerInfo.getStream() <- &messager.StreamResponse{ - Type: "rebalance", - Profile: ProfileToBytes(workerProfile), - NodeID: workerInfo.ID, - } - } - cur++ - } - return true - }) - - log.Warn().Msg("send rebalance data to worker successfully") - return nil -} - -func (r *masterRunner) fetchTestCases() ([]byte, error) { - ticker := time.NewTicker(30 * time.Second) - if len(r.testCaseBytesChan) > 0 { - <-r.testCaseBytesChan - } - r.parseTestCasesChan <- true - select { - case <-ticker.C: - return nil, errors.New("parse testcases timeout") - case testCasesBytes := <-r.testCaseBytesChan: - r.testCasesBytes = testCasesBytes - return testCasesBytes, nil - } -} - -func (r *masterRunner) stop() error { - if r.isStarting() { - r.updateState(StateStopping) - r.server.sendBroadcasts(&genericMessage{Type: "stop"}) - return nil - } else { - return errors.New("already stopped") - } -} - -func (r *masterRunner) onQuiting() { - if r.getState() != StateQuitting { - r.server.sendBroadcasts(&genericMessage{ - Type: "quit", - }) - } - r.updateState(StateQuitting) -} - -func (r *masterRunner) close() { - r.onQuiting() - close(r.closeChan) -} - -func (r *masterRunner) reportStats() { - currentTime := time.Now() - println() - println("==================================== HttpRunner Master for Distributed Load Testing ==================================== ") - println(fmt.Sprintf("Current time: %s, State: %v, Current Available Workers: %v, Target Users: %v, Current Users: %v", - currentTime.Format("2006/01/02 15:04:05"), getStateName(r.getState()), r.server.getAvailableClientsLength(), r.getSpawnCount(), r.server.getCurrentUsers())) - table := tablewriter.NewWriter(os.Stdout) - table.SetColMinWidth(0, 40) - table.SetColMinWidth(1, 10) - table.SetColMinWidth(2, 10) - table.SetHeader([]string{"Worker ID", "IP", "State", "Current Users", "CPU Usage (%)", "Memory Usage (%)"}) - - for _, worker := range r.server.getAllWorkers() { - row := make([]string, 6) - row[0] = worker.ID - row[1] = worker.IP - row[2] = fmt.Sprintf("%v", getStateName(worker.State)) - row[3] = fmt.Sprintf("%v", worker.UserCount) - row[4] = fmt.Sprintf("%.2f", worker.CPUUsage) - row[5] = fmt.Sprintf("%.2f", worker.MemoryUsage) - table.Append(row) - } - table.Render() - println() -} diff --git a/hrp/pkg/boomer/runner_test.go b/hrp/pkg/boomer/runner_test.go deleted file mode 100644 index fcde9734..00000000 --- a/hrp/pkg/boomer/runner_test.go +++ /dev/null @@ -1,552 +0,0 @@ -package boomer - -import ( - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/httprunner/httprunner/v4/hrp/internal/builtin" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/grpc/messager" -) - -type HitOutput struct { - onStart bool - onEvent bool - onStop bool -} - -func (o *HitOutput) OnStart() { - o.onStart = true -} - -func (o *HitOutput) OnEvent(data map[string]interface{}) { - o.onEvent = true -} - -func (o *HitOutput) OnStop() { - o.onStop = true -} - -func TestSafeRun(t *testing.T) { - runner := &runner{} - runner.safeRun(func() { - panic("Runner will catch this panic") - }) -} - -func TestOutputOnStart(t *testing.T) { - hitOutput := &HitOutput{} - hitOutput2 := &HitOutput{} - runner := &runner{} - runner.addOutput(hitOutput) - runner.addOutput(hitOutput2) - runner.outputOnStart() - if !hitOutput.onStart { - t.Error("hitOutput's OnStart has not been called") - } - if !hitOutput2.onStart { - t.Error("hitOutput2's OnStart has not been called") - } -} - -func TestOutputOnEvent(t *testing.T) { - hitOutput := &HitOutput{} - hitOutput2 := &HitOutput{} - runner := &runner{} - runner.addOutput(hitOutput) - runner.addOutput(hitOutput2) - runner.outputOnEvent(nil) - if !hitOutput.onEvent { - t.Error("hitOutput's OnEvent has not been called") - } - if !hitOutput2.onEvent { - t.Error("hitOutput2's OnEvent has not been called") - } -} - -func TestOutputOnStop(t *testing.T) { - hitOutput := &HitOutput{} - hitOutput2 := &HitOutput{} - runner := &runner{} - runner.addOutput(hitOutput) - runner.addOutput(hitOutput2) - runner.outputOnStop() - if !hitOutput.onStop { - t.Error("hitOutput's OnStop has not been called") - } - if !hitOutput2.onStop { - t.Error("hitOutput2's OnStop has not been called") - } -} - -func TestLocalRunner(t *testing.T) { - taskA := &Task{ - Weight: 10, - Fn: func() { - time.Sleep(time.Second) - }, - Name: "TaskA", - } - tasks := []*Task{taskA} - runner := newLocalRunner(2, 2) - runner.setTasks(tasks) - go runner.start() - time.Sleep(4 * time.Second) - runner.stop() -} - -func TestLoopCount(t *testing.T) { - taskA := &Task{ - Weight: 10, - Fn: func() { - time.Sleep(time.Millisecond) - }, - Name: "TaskA", - } - tasks := []*Task{taskA} - runner := newLocalRunner(2, 2) - runner.loop = &Loop{loopCount: 4} - runner.setTasks(tasks) - runner.start() - if !assert.Equal(t, atomic.LoadInt64(&runner.loop.loopCount), atomic.LoadInt64(&runner.loop.finishedCount)) { - t.Fatal() - } -} - -func TestStopNotify(t *testing.T) { - r := &localRunner{ - runner: runner{ - stopChan: make(chan bool), - doneChan: make(chan bool), - }, - } - go func() { - <-r.stopChan - close(r.doneChan) - }() - - notifier := r.stopNotify() - select { - case <-notifier: - t.Fatalf("received unexpected stop notification") - default: - } - r.gracefulStop() - select { - case <-notifier: - default: - t.Fatalf("cannot receive stop notification") - } -} - -func TestSpawnWorkers(t *testing.T) { - taskA := &Task{ - Weight: 10, - Fn: func() { - time.Sleep(time.Second) - }, - Name: "TaskA", - } - tasks := []*Task{taskA} - - runner := newWorkerRunner("localhost", 5557) - defer runner.close() - - runner.client = newClient("localhost", 5557, runner.nodeID) - runner.reset() - runner.setTasks(tasks) - go runner.spawnWorkers(10, 10, runner.stopChan, runner.spawnComplete) - time.Sleep(2 * time.Second) - - currentClients := runner.controller.getCurrentClientsNum() - if currentClients != 10 { - t.Error("Unexpected count", currentClients) - } -} - -func TestSpawnWorkersWithManyTasks(t *testing.T) { - var lock sync.Mutex - taskCalls := map[string]int{} - - createTask := func(name string, weight int) *Task { - return &Task{ - Name: name, - Weight: weight, - Fn: func() { - lock.Lock() - taskCalls[name]++ - lock.Unlock() - }, - } - } - tasks := []*Task{ - createTask("one hundred", 100), - createTask("ten", 10), - createTask("one", 1), - } - - runner := newWorkerRunner("localhost", 5557) - defer runner.close() - - runner.reset() - runner.setTasks(tasks) - runner.client = newClient("localhost", 5557, runner.nodeID) - - const numToSpawn int64 = 20 - - go runner.spawnWorkers(numToSpawn, float64(numToSpawn), runner.stopChan, runner.spawnComplete) - time.Sleep(5 * time.Second) - - currentClients := runner.controller.getCurrentClientsNum() - - assert.Equal(t, numToSpawn, int64(currentClients)) - lock.Lock() - hundreds := taskCalls["one hundred"] - tens := taskCalls["ten"] - ones := taskCalls["one"] - lock.Unlock() - - total := hundreds + tens + ones - t.Logf("total tasks: %d, hundreds: %d, tens: %d, ones: %d\n", - total, hundreds, tens, ones) - - assert.True(t, total > 111) - - assert.True(t, ones > 1) - actPercentage := float64(ones) / float64(total) - expectedPercentage := 1.0 / 111.0 - if actPercentage > 4*expectedPercentage || actPercentage < 0.25*expectedPercentage { - t.Errorf("Unexpected percentage of ones task: exp %v, act %v", expectedPercentage, actPercentage) - } - - assert.True(t, tens > 10) - actPercentage = float64(tens) / float64(total) - expectedPercentage = 10.0 / 111.0 - if actPercentage > 4*expectedPercentage || actPercentage < 0.25*expectedPercentage { - t.Errorf("Unexpected percentage of tens task: exp %v, act %v", expectedPercentage, actPercentage) - } - - assert.True(t, hundreds > 100) - actPercentage = float64(hundreds) / float64(total) - expectedPercentage = 100.0 / 111.0 - if actPercentage > 1 || actPercentage < 0.25*expectedPercentage { - t.Errorf("Unexpected percentage of hundreds task: exp %v, act %v", expectedPercentage, actPercentage) - } -} - -func TestSpawnAndStop(t *testing.T) { - taskA := &Task{ - Fn: func() { - time.Sleep(time.Second) - }, - } - taskB := &Task{ - Fn: func() { - time.Sleep(2 * time.Second) - }, - } - tasks := []*Task{taskA, taskB} - runner := newWorkerRunner("localhost", 5557) - defer runner.close() - runner.client = newClient("localhost", 5557, runner.nodeID) - - runner.setTasks(tasks) - runner.setSpawnCount(10) - runner.setSpawnRate(10) - - go runner.start() - - // wait for spawning goroutines - time.Sleep(5 * time.Second) - if runner.controller.getCurrentClientsNum() != 10 { - t.Error("Number of goroutines mismatches, expected: 10, current count", runner.controller.getCurrentClientsNum()) - } - - msg := <-runner.client.sendChannel() - if msg.Type != "spawning_complete" { - t.Error("Runner should send spawning_complete message when spawning completed, got", msg.Type) - } - go runner.stop() - - runner.onQuiting() - msg = <-runner.client.sendChannel() - if msg.Type != "quit" { - t.Error("Runner should send quit message on quitting, got", msg.Type) - } -} - -func TestStop(t *testing.T) { - taskA := &Task{ - Fn: func() { - time.Sleep(time.Second) - }, - } - tasks := []*Task{taskA} - runner := newWorkerRunner("localhost", 5557) - runner.setTasks(tasks) - runner.reset() - runner.updateState(StateSpawning) - - go runner.stop() - close(runner.doneChan) - time.Sleep(1 * time.Second) - if runner.getState() != StateStopped { - t.Error("Expected runner state to be 5, was", getStateName(runner.getState())) - } -} - -func TestOnSpawnMessage(t *testing.T) { - taskA := &Task{ - Fn: func() { - time.Sleep(time.Second) - }, - } - runner := newWorkerRunner("localhost", 5557) - defer runner.close() - runner.client = newClient("localhost", 5557, runner.nodeID) - runner.updateState(StateInit) - runner.reset() - runner.setTasks([]*Task{taskA}) - runner.setSpawnCount(100) - runner.setSpawnRate(100) - runner.onSpawnMessage(newMessageToWorker("spawn", ProfileToBytes(&Profile{SpawnCount: 20, SpawnRate: 20}), nil, nil)) - - if runner.getSpawnCount() != 20 { - t.Error("workers should be overwrote by onSpawnMessage, expected: 20, was:", runner.controller.spawnCount) - } - if runner.getSpawnRate() != 20 { - t.Error("spawnRate should be overwrote by onSpawnMessage, expected: 20, was:", runner.controller.spawnRate) - } - - runner.onMessage(newGenericMessage("stop", nil, runner.nodeID)) -} - -func TestOnQuitMessage(t *testing.T) { - runner := newWorkerRunner("localhost", 5557) - runner.client = newClient("localhost", 5557, "test") - runner.updateState(StateInit) - - runner.onMessage(newGenericMessage("quit", nil, runner.nodeID)) - <-runner.closeChan - - runner.updateState(StateRunning) - runner.reset() - runner.closeChan = make(chan bool) - runner.client.shutdownChan = make(chan bool) - go runner.onMessage(newGenericMessage("quit", nil, runner.nodeID)) - close(runner.doneChan) - <-runner.closeChan - runner.onQuiting() - if runner.getState() != StateQuitting { - t.Error("Runner's state should be StateQuitting") - } - - runner.updateState(StateStopped) - runner.closeChan = make(chan bool) - runner.reset() - runner.client.shutdownChan = make(chan bool) - runner.onMessage(newGenericMessage("quit", nil, runner.nodeID)) - <-runner.closeChan - runner.onQuiting() - if runner.getState() != StateQuitting { - t.Error("Runner's state should be StateQuitting") - } -} - -func TestOnMessage(t *testing.T) { - taskA := &Task{ - Fn: func() { - time.Sleep(time.Second) - }, - } - taskB := &Task{ - Fn: func() { - time.Sleep(2 * time.Second) - }, - } - tasks := []*Task{taskA, taskB} - - runner := newWorkerRunner("localhost", 5557) - runner.client = newClient("localhost", 5557, runner.nodeID) - runner.updateState(StateInit) - runner.setTasks(tasks) - - // start spawning - runner.onMessage(newMessageToWorker("spawn", ProfileToBytes(&Profile{SpawnCount: 10, SpawnRate: 10}), nil, nil)) - go runner.start() - - msg := <-runner.client.sendChannel() - if msg.Type != "spawning" { - t.Error("Runner should send spawning message when starting spawn, got", msg.Type) - } - - // spawn complete and running - time.Sleep(5 * time.Second) - if runner.controller.getCurrentClientsNum() != 10 { - t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.controller.getCurrentClientsNum()) - } - msg = <-runner.client.sendChannel() - if msg.Type != "spawning_complete" { - t.Error("Runner should send spawning_complete message when spawn completed, got", msg.Type) - } - if runner.getState() != StateRunning { - t.Error("State of runner is not running after spawn, got", getStateName(runner.getState())) - } - - // increase goroutines while running - runner.onMessage(newMessageToWorker("rebalance", ProfileToBytes(&Profile{SpawnCount: 15, SpawnRate: 15}), nil, nil)) - runner.controller.rebalance <- true - - time.Sleep(2 * time.Second) - if runner.getState() != StateRunning { - t.Error("State of runner is not running after spawn, got", getStateName(runner.getState())) - } - if runner.controller.getCurrentClientsNum() != 15 { - t.Error("Number of goroutines mismatches, expected: 15, current count:", runner.controller.getCurrentClientsNum()) - } - - // stop all the workers - runner.onMessage(newGenericMessage("stop", nil, runner.nodeID)) - if runner.getState() != StateStopped { - t.Error("State of runner is not stopped, got", getStateName(runner.getState())) - } - msg = <-runner.client.sendChannel() - if msg.Type != "client_stopped" { - t.Error("Runner should send client_stopped message, got", msg.Type) - } - - time.Sleep(3 * time.Second) - - // spawn again - runner.onMessage(newMessageToWorker("spawn", ProfileToBytes(&Profile{SpawnCount: 10, SpawnRate: 10}), nil, nil)) - go runner.start() - - msg = <-runner.client.sendChannel() - if msg.Type != "spawning" { - t.Error("Runner should send spawning message when starting spawn, got", msg.Type) - } - - // spawn complete and running - time.Sleep(5 * time.Second) - if runner.controller.getCurrentClientsNum() != 10 { - t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.controller.getCurrentClientsNum()) - } - if runner.getState() != StateRunning { - t.Error("State of runner is not running after spawn, got", getStateName(runner.getState())) - } - msg = <-runner.client.sendChannel() - if msg.Type != "spawning_complete" { - t.Error("Runner should send spawning_complete message when spawn completed, got", msg.Type) - } - - // stop all the workers - runner.onMessage(newGenericMessage("stop", nil, runner.nodeID)) - if runner.getState() != StateStopped { - t.Error("State of runner is not stopped, got", getStateName(runner.getState())) - } - msg = <-runner.client.sendChannel() - if msg.Type != "client_stopped" { - t.Error("Runner should send client_stopped message, got", msg.Type) - } - - time.Sleep(3 * time.Second) - // quit - runner.onMessage(newGenericMessage("quit", nil, runner.nodeID)) -} - -func TestClientListener(t *testing.T) { - runner := newMasterRunner("localhost", 5557) - defer runner.close() - runner.updateState(StateInit) - runner.setSpawnCount(10) - runner.setSpawnRate(10) - go runner.stateMachine() - go runner.clientListener() - runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 3, stream: make(chan *messager.StreamResponse, 10)}) - runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 3, stream: make(chan *messager.StreamResponse, 10)}) - runner.server.recvChannel() <- &genericMessage{ - Type: typeClientReady, - NodeID: "testID1", - } - worker1, ok := runner.server.getClients().Load("testID1") - if !ok { - t.Fatal("error") - } - workerInfo1, ok := worker1.(*WorkerNode) - if !ok { - t.Fatal("error") - } - time.Sleep(time.Second) - if workerInfo1.getState() != StateInit { - t.Error("State of worker runner is not init, got", workerInfo1.getState()) - } - runner.server.recvChannel() <- &genericMessage{ - Type: typeClientStopped, - NodeID: "testID2", - } - runner.updateState(StateRunning) - worker2, ok := runner.server.getClients().Load("testID2") - if !ok { - t.Fatal("error") - } - workerInfo2, ok := worker2.(*WorkerNode) - if !ok { - t.Fatal("error") - } - time.Sleep(time.Second) - if workerInfo2.getState() != StateStopped { - t.Error("State of worker runner is not stopped, got", workerInfo2.getState()) - } - runner.server.recvChannel() <- &genericMessage{ - Type: typeClientStopped, - NodeID: "testID1", - } - time.Sleep(time.Second) - if runner.getState() != StateStopped { - t.Error("State of master runner is not stopped, got", getStateName(runner.getState())) - } -} - -func TestHeartbeatWorker(t *testing.T) { - runner := newMasterRunner("localhost", 5557) - defer runner.close() - runner.updateState(StateInit) - runner.setSpawnCount(10) - runner.setSpawnRate(10) - runner.server.clients.Store("testID1", &WorkerNode{ID: "testID1", Heartbeat: 1, State: StateInit, stream: make(chan *messager.StreamResponse, 10)}) - runner.server.clients.Store("testID2", &WorkerNode{ID: "testID2", Heartbeat: 1, State: StateInit, stream: make(chan *messager.StreamResponse, 10)}) - go runner.clientListener() - go runner.heartbeatWorker() - time.Sleep(4 * time.Second) - worker1, ok := runner.server.getClients().Load("testID1") - if !ok { - t.Fatal() - } - workerInfo1, ok := worker1.(*WorkerNode) - if !ok { - t.Fatal() - } - if workerInfo1.getState() != StateMissing { - t.Error("expected state of worker runner is missing, but got", getStateName(workerInfo1.getState())) - } - runner.server.recvChannel() <- &genericMessage{ - Type: typeHeartbeat, - NodeID: "testID2", - Data: map[string][]byte{"state": builtin.Int64ToBytes(3)}, - } - worker2, ok := runner.server.getClients().Load("testID2") - if !ok { - t.Fatal() - } - workerInfo2, ok := worker2.(*WorkerNode) - if !ok { - t.Fatal() - } - time.Sleep(time.Second) - if workerInfo2.getState() == StateMissing { - t.Error("expected state of worker runner is not missing, but got missing") - } -} diff --git a/hrp/pkg/boomer/server_grpc.go b/hrp/pkg/boomer/server_grpc.go deleted file mode 100644 index f795cac5..00000000 --- a/hrp/pkg/boomer/server_grpc.go +++ /dev/null @@ -1,577 +0,0 @@ -package boomer - -import ( - "context" - "fmt" - "net" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/rs/zerolog/log" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/peer" - "google.golang.org/grpc/reflection" - "google.golang.org/grpc/status" - - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/data" - "github.com/httprunner/httprunner/v4/hrp/pkg/boomer/grpc/messager" -) - -type WorkerNode struct { - ID string `json:"id"` - IP string `json:"ip"` - OS string `json:"os"` - Arch string `json:"arch"` - State int32 `json:"state"` - Heartbeat int32 `json:"heartbeat"` - UserCount int64 `json:"user_count"` - WorkerCPUUsage float64 `json:"worker_cpu_usage"` - CPUUsage float64 `json:"cpu_usage"` - CPUWarningEmitted bool `json:"cpu_warning_emitted"` - WorkerMemoryUsage float64 `json:"worker_memory_usage"` - MemoryUsage float64 `json:"memory_usage"` - stream chan *messager.StreamResponse - mutex sync.RWMutex - disconnectedChan chan bool -} - -func newWorkerNode(id, ip, os, arch string) *WorkerNode { - stream := make(chan *messager.StreamResponse, 100) - return &WorkerNode{State: StateInit, ID: id, IP: ip, OS: os, Arch: arch, Heartbeat: 3, stream: stream, disconnectedChan: make(chan bool)} -} - -func (w *WorkerNode) getState() int32 { - return atomic.LoadInt32(&w.State) -} - -func (w *WorkerNode) setState(state int32) { - atomic.StoreInt32(&w.State, state) -} - -func (w *WorkerNode) isStarting() bool { - return w.getState() == StateRunning || w.getState() == StateSpawning -} - -func (w *WorkerNode) isStopping() bool { - return w.getState() == StateStopping -} - -func (w *WorkerNode) isAvailable() bool { - state := w.getState() - return state != StateMissing && state != StateQuitting -} - -func (w *WorkerNode) isReady() bool { - state := w.getState() - return state == StateInit || state == StateStopped -} - -func (w *WorkerNode) updateHeartbeat(heartbeat int32) { - atomic.StoreInt32(&w.Heartbeat, heartbeat) -} - -func (w *WorkerNode) getHeartbeat() int32 { - return atomic.LoadInt32(&w.Heartbeat) -} - -func (w *WorkerNode) updateUserCount(spawnCount int64) { - atomic.StoreInt64(&w.UserCount, spawnCount) -} - -func (w *WorkerNode) getUserCount() int64 { - return atomic.LoadInt64(&w.UserCount) -} - -func (w *WorkerNode) updateCPUUsage(cpuUsage float64) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.CPUUsage = cpuUsage -} - -func (w *WorkerNode) getCPUUsage() float64 { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.CPUUsage -} - -func (w *WorkerNode) updateWorkerCPUUsage(workerCPUUsage float64) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.WorkerCPUUsage = workerCPUUsage -} - -func (w *WorkerNode) getWorkerCPUUsage() float64 { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.WorkerCPUUsage -} - -func (w *WorkerNode) updateCPUWarningEmitted(cpuWarningEmitted bool) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.CPUWarningEmitted = cpuWarningEmitted -} - -func (w *WorkerNode) getCPUWarningEmitted() bool { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.CPUWarningEmitted -} - -func (w *WorkerNode) updateWorkerMemoryUsage(workerMemoryUsage float64) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.WorkerMemoryUsage = workerMemoryUsage -} - -func (w *WorkerNode) getWorkerMemoryUsage() float64 { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.WorkerMemoryUsage -} - -func (w *WorkerNode) updateMemoryUsage(memoryUsage float64) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.MemoryUsage = memoryUsage -} - -func (w *WorkerNode) getMemoryUsage() float64 { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.MemoryUsage -} - -func (w *WorkerNode) setStream(stream chan *messager.StreamResponse) { - w.mutex.Lock() - defer w.mutex.Unlock() - w.stream = stream -} - -func (w *WorkerNode) getStream() chan *messager.StreamResponse { - w.mutex.RLock() - defer w.mutex.RUnlock() - return w.stream -} - -func (w *WorkerNode) getWorkerInfo() WorkerNode { - w.mutex.RLock() - defer w.mutex.RUnlock() - return WorkerNode{ - ID: w.ID, - IP: w.IP, - OS: w.OS, - Arch: w.Arch, - State: w.getState(), - Heartbeat: w.getHeartbeat(), - UserCount: w.getUserCount(), - WorkerCPUUsage: w.getWorkerCPUUsage(), - CPUUsage: w.getCPUUsage(), - CPUWarningEmitted: w.getCPUWarningEmitted(), - WorkerMemoryUsage: w.getWorkerMemoryUsage(), - MemoryUsage: w.getMemoryUsage(), - } -} - -type grpcServer struct { - messager.UnimplementedMessageServer - masterHost string - masterPort int - server *grpc.Server - clients *sync.Map - - fromWorker chan *genericMessage - disconnectedChan chan bool - shutdownChan chan bool - - wg sync.WaitGroup -} - -var ( - errMissingMetadata = status.Errorf(codes.InvalidArgument, "missing metadata") - errInvalidToken = status.Errorf(codes.Unauthenticated, "invalid token") -) - -func logger(format string, a ...interface{}) { - // FIXME: support server-side and client-side logging to files - log.Info().Msg(fmt.Sprintf(format, a...)) -} - -// valid validates the authorization. -func valid(authorization []string) bool { - if len(authorization) < 1 { - return false - } - token := strings.TrimPrefix(authorization[0], "Bearer ") - return token == "httprunner-secret-token" -} - -func serverUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - // authentication (token verification) - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - return nil, errMissingMetadata - } - if !valid(md["authorization"]) { - return nil, errInvalidToken - } - m, err := handler(ctx, req) - if err != nil { - logger("RPC failed with error %v", err) - } - return m, err -} - -// serverWrappedStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and -// SendMsg method call. -type serverWrappedStream struct { - grpc.ServerStream -} - -func (w *serverWrappedStream) RecvMsg(m interface{}) error { - logger("Receive a message (Type: %T) at %s", m, time.Now().Format(time.RFC3339)) - return w.ServerStream.RecvMsg(m) -} - -func (w *serverWrappedStream) SendMsg(m interface{}) error { - logger("Send a message (Type: %T) at %v", m, time.Now().Format(time.RFC3339)) - return w.ServerStream.SendMsg(m) -} - -func newServerWrappedStream(s grpc.ServerStream) grpc.ServerStream { - return &serverWrappedStream{s} -} - -func serverStreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - // authentication (token verification) - md, ok := metadata.FromIncomingContext(ss.Context()) - if !ok { - return errMissingMetadata - } - if !valid(md["authorization"]) { - return errInvalidToken - } - - err := handler(srv, newServerWrappedStream(ss)) - if err != nil { - logger("RPC failed with error %v", err) - } - return err -} - -func newServer(masterHost string, masterPort int) (server *grpcServer) { - log.Info().Msg("Boomer is built with grpc support.") - server = &grpcServer{ - masterHost: masterHost, - masterPort: masterPort, - clients: &sync.Map{}, - fromWorker: make(chan *genericMessage, 100), - disconnectedChan: make(chan bool), - shutdownChan: make(chan bool), - wg: sync.WaitGroup{}, - } - return server -} - -func (s *grpcServer) start() (err error) { - addr := fmt.Sprintf("%v:%v", s.masterHost, s.masterPort) - // Create tls based credential. - creds, err := credentials.NewServerTLSFromFile(data.Path("x509/server_cert.pem"), data.Path("x509/server_key.pem")) - if err != nil { - log.Fatal().Msg(fmt.Sprintf("failed to load key pair: %s", err)) - } - opts := []grpc.ServerOption{ - grpc.UnaryInterceptor(serverUnaryInterceptor), - grpc.StreamInterceptor(serverStreamInterceptor), - // Enable TLS for all incoming connections. - grpc.Creds(creds), - } - lis, err := net.Listen("tcp", addr) - if err != nil { - log.Error().Err(err).Msg("failed to listen") - return - } - // create gRPC server - s.server = grpc.NewServer(opts...) - // register message server - messager.RegisterMessageServer(s.server, s) - reflection.Register(s.server) - // start grpc server - go func() { - err = s.server.Serve(lis) - if err != nil { - log.Error().Err(err).Msg("failed to serve") - return - } - }() - return nil -} - -func (s *grpcServer) Register(ctx context.Context, req *messager.RegisterRequest) (*messager.RegisterResponse, error) { - // get client ip - p, _ := peer.FromContext(ctx) - clientIp := strings.Split(p.Addr.String(), ":")[0] - // store worker information - wn := newWorkerNode(req.NodeID, clientIp, req.Os, req.Arch) - s.clients.Store(req.NodeID, wn) - log.Warn().Str("worker id", req.NodeID).Msg("worker joined") - return &messager.RegisterResponse{Code: "0", Message: "register successful"}, nil -} - -func (s *grpcServer) SignOut(_ context.Context, req *messager.SignOutRequest) (*messager.SignOutResponse, error) { - // delete worker information - s.clients.Delete(req.NodeID) - log.Warn().Str("worker id", req.NodeID).Msg("worker quited") - return &messager.SignOutResponse{Code: "0", Message: "sign out successful"}, nil -} - -func (s *grpcServer) validClientToken(token string) bool { - _, ok := s.clients.Load(token) - return ok -} - -func (s *grpcServer) BidirectionalStreamingMessage(srv messager.Message_BidirectionalStreamingMessageServer) error { - s.wg.Add(1) - defer s.wg.Done() - token, ok := extractToken(srv.Context()) - if !ok { - return status.Error(codes.Unauthenticated, "missing token header") - } - - ok = s.validClientToken(token) - if !ok { - return status.Error(codes.Unauthenticated, "invalid token") - } - - go s.sendMsg(srv, token) -FOR: - for { - select { - case <-srv.Context().Done(): - break FOR - case <-s.disconnectedChannel(): - break FOR - default: - msg, err := srv.Recv() - if st, ok := status.FromError(err); ok { - switch st.Code() { - case codes.OK: - s.fromWorker <- newGenericMessage(msg.Type, msg.Data, msg.NodeID) - log.Info(). - Str("nodeID", msg.NodeID). - Str("type", msg.Type). - Interface("data", msg.Data). - Msg("receive data from worker") - case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded: - s.fromWorker <- newQuitMessage(token) - break FOR - default: - log.Error().Err(err).Msg("failed to get stream from client") - break FOR - } - } - } - } - - log.Info().Str("worker id", token).Msg("bidirectional stream closed") - return nil -} - -func (s *grpcServer) sendMsg(srv messager.Message_BidirectionalStreamingMessageServer, id string) { - stream := s.getWorkersByID(id).getStream() - for { - select { - case <-srv.Context().Done(): - return - case <-s.disconnectedChannel(): - return - case res := <-stream: - if s, ok := status.FromError(srv.Send(res)); ok { - switch s.Code() { - case codes.OK: - log.Info(). - Str("nodeID", res.NodeID). - Str("type", res.Type). - Interface("data", res.Data). - Interface("profile", res.Profile). - Msg("send data to worker") - case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded: - log.Warn().Msg(fmt.Sprintf("client (%s) terminated connection", id)) - return - default: - log.Warn().Msg(fmt.Sprintf("failed to send to client (%s): %v", id, s.Err())) - return - } - } - } - } -} - -func (s *grpcServer) sendBroadcasts(msg *genericMessage) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if !workerInfo.isAvailable() { - return true - } - workerInfo.getStream() <- &messager.StreamResponse{ - Type: msg.Type, - Profile: msg.Profile, - Data: msg.Data, - NodeID: workerInfo.ID, - Tasks: msg.Tasks, - } - } - return true - }) -} - -func (s *grpcServer) stopServer(ctx context.Context) { - ch := make(chan struct{}) - go func() { - defer close(ch) - // close listeners to stop accepting new connections, - // will block on any existing transports - s.server.GracefulStop() - }() - - // wait until all pending RPCs are finished - select { - case <-ch: - case <-ctx.Done(): - // took too long, manually close open transports - // e.g. watch streams - s.server.Stop() - - // concurrent GracefulStop should be interrupted - <-ch - } -} - -func (s *grpcServer) close() { - // close client requests with request timeout - timeout := 2 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - s.stopServer(ctx) - cancel() - - // disconnecting workers - close(s.disconnectedChan) - - // waiting to close bidirectional stream - s.wg.Wait() -} - -func (s *grpcServer) recvChannel() chan *genericMessage { - return s.fromWorker -} - -func (s *grpcServer) shutdownChannel() chan bool { - return s.shutdownChan -} - -func (s *grpcServer) disconnectedChannel() chan bool { - return s.disconnectedChan -} - -func (s *grpcServer) getWorkersByState(state int32) (wns []*WorkerNode) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.getState() == state { - wns = append(wns, workerInfo) - } - } - return true - }) - return wns -} - -func (s *grpcServer) getWorkersByID(id string) (wn *WorkerNode) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.ID == id { - wn = workerInfo - } - } - return true - }) - return wn -} - -func (s *grpcServer) getWorkersLengthByState(state int32) (l int) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.getState() == state { - l++ - } - } - return true - }) - return -} - -func (s *grpcServer) getAllWorkers() (wns []WorkerNode) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - wns = append(wns, workerInfo.getWorkerInfo()) - } - return true - }) - return wns -} - -func (s *grpcServer) getClients() *sync.Map { - return s.clients -} - -func (s *grpcServer) getAvailableClientsLength() (l int) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.isAvailable() { - l++ - } - } - return true - }) - return -} - -func (s *grpcServer) getReadyClientsLength() (l int) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.isReady() { - l++ - } - } - return true - }) - return -} - -func (s *grpcServer) getStartingClientsLength() (l int) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.isStarting() { - l++ - } - } - return true - }) - return -} - -func (s *grpcServer) getCurrentUsers() (l int) { - s.clients.Range(func(key, value interface{}) bool { - if workerInfo, ok := value.(*WorkerNode); ok { - if workerInfo.isStarting() { - l += int(workerInfo.getUserCount()) - } - } - return true - }) - return -} diff --git a/hrp/pkg/boomer/server_grpc_test.go b/hrp/pkg/boomer/server_grpc_test.go deleted file mode 100644 index 853e847e..00000000 --- a/hrp/pkg/boomer/server_grpc_test.go +++ /dev/null @@ -1 +0,0 @@ -package boomer diff --git a/hrp/pkg/boomer/stats.go b/hrp/pkg/boomer/stats.go deleted file mode 100644 index 043246cb..00000000 --- a/hrp/pkg/boomer/stats.go +++ /dev/null @@ -1,302 +0,0 @@ -package boomer - -import ( - "sync/atomic" - "time" - - "github.com/httprunner/httprunner/v4/hrp/internal/json" -) - -type transaction struct { - name string - success bool - elapsedTime int64 - contentSize int64 -} - -type requestSuccess struct { - requestType string - name string - responseTime int64 - responseLength int64 -} - -type requestFailure struct { - requestType string - name string - responseTime int64 - errMsg string -} - -type requestStats struct { - entries map[string]*statsEntry - errors map[string]*statsError - total *statsEntry - startTime int64 - - transactionChan chan *transaction - transactionPassed int64 // accumulated number of passed transactions - transactionFailed int64 // accumulated number of failed transactions - - requestSuccessChan chan *requestSuccess - requestFailureChan chan *requestFailure -} - -func newRequestStats() (stats *requestStats) { - entries := make(map[string]*statsEntry) - errors := make(map[string]*statsError) - - stats = &requestStats{ - entries: entries, - errors: errors, - } - stats.transactionChan = make(chan *transaction, 100) - stats.requestSuccessChan = make(chan *requestSuccess, 100) - stats.requestFailureChan = make(chan *requestFailure, 100) - - stats.total = &statsEntry{ - Name: "Total", - Method: "", - } - stats.total.reset() - - return stats -} - -func (s *requestStats) logTransaction(name string, success bool, responseTime int64, contentLength int64) { - if success { - s.transactionPassed++ - } else { - s.transactionFailed++ - s.get(name, "transaction").logFailures() - } - s.get(name, "transaction").log(responseTime, contentLength) -} - -func (s *requestStats) logRequest(method, name string, responseTime int64, contentLength int64) { - if method != "testcase" { - s.total.log(responseTime, contentLength) - } - s.get(name, method).log(responseTime, contentLength) -} - -func (s *requestStats) logError(method, name, err string) { - if method != "testcase" { - s.total.logFailures() - } - s.get(name, method).logFailures() - - // store error in errors map - key := genMD5(method, name, err) - entry, ok := s.errors[key] - if !ok { - entry = &statsError{ - name: name, - method: method, - errMsg: err, - } - s.errors[key] = entry - } - entry.occured() -} - -func (s *requestStats) get(name string, method string) (entry *statsEntry) { - entry, ok := s.entries[name+method] - if !ok { - newEntry := &statsEntry{ - Name: name, - Method: method, - ResponseTimes: make(map[int64]int64), - } - s.entries[name+method] = newEntry - return newEntry - } - return entry -} - -func (s *requestStats) clearAll() { - s.total = &statsEntry{ - Name: "Total", - Method: "", - } - s.total.reset() - s.transactionPassed = 0 - s.transactionFailed = 0 - s.entries = make(map[string]*statsEntry) - s.errors = make(map[string]*statsError) - s.startTime = time.Now().Unix() -} - -func (s *requestStats) serializeStats() []interface{} { - entries := make([]interface{}, 0, len(s.entries)) - for _, v := range s.entries { - if !(v.NumRequests == 0 && v.NumFailures == 0) { - entries = append(entries, v.getStrippedReport()) - } - } - return entries -} - -func (s *requestStats) serializeErrors() map[string]map[string]interface{} { - errors := make(map[string]map[string]interface{}) - for k, v := range s.errors { - errors[k] = v.toMap() - } - return errors -} - -func (s *requestStats) collectReportData() map[string]interface{} { - data := make(map[string]interface{}) - data["transactions"] = map[string]int64{ - "passed": s.transactionPassed, - "failed": s.transactionFailed, - } - data["stats"] = s.serializeStats() - data["stats_total"] = s.total.serialize() - data["errors"] = s.serializeErrors() - s.errors = make(map[string]*statsError) - return data -} - -// statsEntry represents a single stats entry (name and method) -type statsEntry struct { - // Name (URL) of this stats entry - Name string `json:"name"` - // Method (GET, POST, PUT, etc.) - Method string `json:"method"` - // The number of requests made - NumRequests int64 `json:"num_requests"` - // Number of failed request - NumFailures int64 `json:"num_failures"` - // Total sum of the response times - TotalResponseTime int64 `json:"total_response_time"` - // Minimum response time - MinResponseTime int64 `json:"min_response_time"` - // Maximum response time - MaxResponseTime int64 `json:"max_response_time"` - // A {response_time => count} dict that holds the response time distribution of all the requests - // The keys (the response time in ms) are rounded to store 1, 2, ... 9, 10, 20. .. 90, - // 100, 200 .. 900, 1000, 2000 ... 9000, in order to save memory. - // This dict is used to calculate the median and percentile response times. - ResponseTimes map[int64]int64 `json:"response_times"` - // The sum of the content length of all the requests for this entry - TotalContentLength int64 `json:"total_content_length"` - // Time of the first request for this entry - StartTime int64 `json:"start_time"` - // Time of the last request for this entry - LastRequestTimestamp int64 `json:"last_request_timestamp"` - // Boomer doesn't allow None response time for requests like locust. - // num_none_requests is added to keep compatible with locust. - NumNoneRequests int64 `json:"num_none_requests"` -} - -func (s *statsEntry) resetStartTime() { - atomic.StoreInt64(&s.StartTime, time.Duration(time.Now().UnixNano()).Milliseconds()) -} - -func (s *statsEntry) reset() { - atomic.StoreInt64(&s.StartTime, time.Duration(time.Now().UnixNano()).Milliseconds()) - s.NumRequests = 0 - s.NumFailures = 0 - s.TotalResponseTime = 0 - s.ResponseTimes = make(map[int64]int64) - s.MinResponseTime = 0 - s.MaxResponseTime = 0 - s.LastRequestTimestamp = time.Duration(time.Now().UnixNano()).Milliseconds() - s.TotalContentLength = 0 -} - -func (s *statsEntry) log(responseTime int64, contentLength int64) { - s.NumRequests++ - - s.logTimeOfRequest() - s.logResponseTime(responseTime) - - s.TotalContentLength += contentLength -} - -func (s *statsEntry) logTimeOfRequest() { - s.LastRequestTimestamp = time.Duration(time.Now().UnixNano()).Milliseconds() -} - -func (s *statsEntry) logResponseTime(responseTime int64) { - s.TotalResponseTime += responseTime - - if s.MinResponseTime == 0 { - s.MinResponseTime = responseTime - } - - if responseTime < s.MinResponseTime { - s.MinResponseTime = responseTime - } - - if responseTime > s.MaxResponseTime { - s.MaxResponseTime = responseTime - } - - var roundedResponseTime int64 - - // to avoid too much data that has to be transferred to the master node when - // running in distributed mode, we save the response time rounded in a dict - // so that 147 becomes 150, 3432 becomes 3400 and 58760 becomes 59000 - // see also locust's stats.py - if responseTime < 100 { - roundedResponseTime = responseTime - } else if responseTime < 1000 { - roundedResponseTime = int64(round(float64(responseTime), .5, -1)) - } else if responseTime < 10000 { - roundedResponseTime = int64(round(float64(responseTime), .5, -2)) - } else { - roundedResponseTime = int64(round(float64(responseTime), .5, -3)) - } - - _, ok := s.ResponseTimes[roundedResponseTime] - if !ok { - s.ResponseTimes[roundedResponseTime] = 1 - } else { - s.ResponseTimes[roundedResponseTime]++ - } -} - -func (s *statsEntry) logFailures() { - s.NumFailures++ -} - -func (s *statsEntry) serialize() map[string]interface{} { - var result map[string]interface{} - val, err := json.Marshal(s) - if err != nil { - return nil - } - err = json.Unmarshal(val, &result) - if err != nil { - return nil - } - return result -} - -func (s *statsEntry) getStrippedReport() map[string]interface{} { - report := s.serialize() - s.reset() - return report -} - -type statsError struct { - name string - method string - errMsg string - occurrences int64 -} - -func (err *statsError) occured() { - err.occurrences++ -} - -func (err *statsError) toMap() map[string]interface{} { - m := make(map[string]interface{}) - m["method"] = err.method - m["name"] = err.name - m["error"] = err.errMsg - m["occurrences"] = err.occurrences - return m -} diff --git a/hrp/pkg/boomer/stats_test.go b/hrp/pkg/boomer/stats_test.go deleted file mode 100644 index 4a8491ca..00000000 --- a/hrp/pkg/boomer/stats_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package boomer - -import ( - "testing" -) - -func TestLogRequest(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 2, 30) - newStats.logRequest("http", "success", 3, 40) - newStats.logRequest("http", "success", 2, 40) - newStats.logRequest("http", "success", 1, 20) - entry := newStats.get("success", "http") - - if entry.NumRequests != 4 { - t.Error("numRequests is wrong, expected: 4, got:", entry.NumRequests) - } - if entry.MinResponseTime != 1 { - t.Error("minResponseTime is wrong, expected: 1, got:", entry.MinResponseTime) - } - if entry.MaxResponseTime != 3 { - t.Error("maxResponseTime is wrong, expected: 3, got:", entry.MaxResponseTime) - } - if entry.TotalResponseTime != 8 { - t.Error("totalResponseTime is wrong, expected: 8, got:", entry.TotalResponseTime) - } - if entry.TotalContentLength != 130 { - t.Error("totalContentLength is wrong, expected: 130, got:", entry.TotalContentLength) - } - - // check newStats.total - if newStats.total.NumRequests != 4 { - t.Error("newStats.total.numRequests is wrong, expected: 4, got:", newStats.total.NumRequests) - } - if newStats.total.MinResponseTime != 1 { - t.Error("newStats.total.minResponseTime is wrong, expected: 1, got:", newStats.total.MinResponseTime) - } - if newStats.total.MaxResponseTime != 3 { - t.Error("newStats.total.maxResponseTime is wrong, expected: 3, got:", newStats.total.MaxResponseTime) - } - if newStats.total.TotalResponseTime != 8 { - t.Error("newStats.total.totalResponseTime is wrong, expected: 8, got:", newStats.total.TotalResponseTime) - } - if newStats.total.TotalContentLength != 130 { - t.Error("newStats.total.totalContentLength is wrong, expected: 130, got:", newStats.total.TotalContentLength) - } -} - -func BenchmarkLogRequest(b *testing.B) { - newStats := newRequestStats() - for i := 0; i < b.N; i++ { - newStats.logRequest("http", "success", 2, 30) - } -} - -func TestRoundedResponseTime(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 147, 1) - newStats.logRequest("http", "success", 3432, 1) - newStats.logRequest("http", "success", 58760, 1) - entry := newStats.get("success", "http") - responseTimes := entry.ResponseTimes - - if len(responseTimes) != 3 { - t.Error("len(responseTimes) is wrong, expected: 3, got:", len(responseTimes)) - } - - if val, ok := responseTimes[150]; !ok || val != 1 { - t.Error("Rounded response time should be", 150) - } - - if val, ok := responseTimes[3400]; !ok || val != 1 { - t.Error("Rounded response time should be", 3400) - } - - if val, ok := responseTimes[59000]; !ok || val != 1 { - t.Error("Rounded response time should be", 59000) - } -} - -func TestLogError(t *testing.T) { - newStats := newRequestStats() - newStats.logError("http", "failure", "500 error") - newStats.logError("http", "failure", "400 error") - newStats.logError("http", "failure", "400 error") - entry := newStats.get("failure", "http") - - if entry.NumFailures != 3 { - t.Error("numFailures is wrong, expected: 3, got:", entry.NumFailures) - } - - if newStats.total.NumFailures != 3 { - t.Error("newStats.total.numFailures is wrong, expected: 3, got:", newStats.total.NumFailures) - } - - // md5("httpfailure500 error") = 547c38e4e4742c1c581f9e2809ba4f55 - err500 := newStats.errors["547c38e4e4742c1c581f9e2809ba4f55"] - if err500.errMsg != "500 error" { - t.Error("Error message is wrong, expected: 500 error, got:", err500.errMsg) - } - if err500.occurrences != 1 { - t.Error("Error occurrences is wrong, expected: 1, got:", err500.occurrences) - } - - // md5("httpfailure400 error") = f391c310401ad8e10e929f2ee1a614e4 - err400 := newStats.errors["f391c310401ad8e10e929f2ee1a614e4"] - if err400.errMsg != "400 error" { - t.Error("Error message is wrong, expected: 400 error, got:", err400.errMsg) - } - if err400.occurrences != 2 { - t.Error("Error occurrences is wrong, expected: 2, got:", err400.occurrences) - } -} - -func BenchmarkLogError(b *testing.B) { - newStats := newRequestStats() - for i := 0; i < b.N; i++ { - // LogError use md5 to calculate hash keys, it may slow down the only goroutine, - // which consumes both requestSuccessChannel and requestFailureChannel. - newStats.logError("http", "failure", "500 error") - } -} - -func TestClearAll(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 1, 20) - newStats.clearAll() - - if newStats.total.NumRequests != 0 { - t.Error("After clearAll(), newStats.total.numRequests is wrong, expected: 0, got:", newStats.total.NumRequests) - } -} - -func TestClearAllByChannel(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 1, 20) - newStats.clearAll() - - if newStats.total.NumRequests != 0 { - t.Error("After clearAll(), newStats.total.numRequests is wrong, expected: 0, got:", newStats.total.NumRequests) - } -} - -func TestSerializeStats(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 1, 20) - - serialized := newStats.serializeStats() - if len(serialized) != 1 { - t.Error("The length of serialized results is wrong, expected: 1, got:", len(serialized)) - return - } - - first := serialized[0] - entry, err := deserializeStatsEntry(first) - if err != nil { - t.Fatal() - } - - if entry.Name != "success" { - t.Error("The name is wrong, expected:", "success", "got:", entry.Name) - } - if entry.Method != "http" { - t.Error("The method is wrong, expected:", "http", "got:", entry.Method) - } - if entry.NumRequests != int64(1) { - t.Error("The num_requests is wrong, expected:", 1, "got:", entry.NumRequests) - } - if entry.NumFailures != int64(0) { - t.Error("The num_failures is wrong, expected:", 0, "got:", entry.NumFailures) - } -} - -func TestSerializeErrors(t *testing.T) { - newStats := newRequestStats() - newStats.logError("http", "failure", "500 error") - newStats.logError("http", "failure", "400 error") - newStats.logError("http", "failure", "400 error") - serialized := newStats.serializeErrors() - - if len(serialized) != 2 { - t.Error("The length of serialized results is wrong, expected: 2, got:", len(serialized)) - return - } - - for key, value := range serialized { - if key == "f391c310401ad8e10e929f2ee1a614e4" { - err := value["error"].(string) - if err != "400 error" { - t.Error("expected: 400 error, got:", err) - } - occurrences := value["occurrences"].(int64) - if occurrences != int64(2) { - t.Error("expected: 2, got:", occurrences) - } - } - } -} - -func TestCollectReportData(t *testing.T) { - newStats := newRequestStats() - newStats.logRequest("http", "success", 2, 30) - newStats.logError("http", "failure", "500 error") - result := newStats.collectReportData() - - if _, ok := result["stats"]; !ok { - t.Error("Key stats not found") - } - if _, ok := result["stats_total"]; !ok { - t.Error("Key stats not found") - } - if _, ok := result["errors"]; !ok { - t.Error("Key stats not found") - } -} diff --git a/hrp/pkg/boomer/task.go b/hrp/pkg/boomer/task.go deleted file mode 100644 index e913d093..00000000 --- a/hrp/pkg/boomer/task.go +++ /dev/null @@ -1,13 +0,0 @@ -package boomer - -// Task is like the "Locust object" in locust, the python version. -// When boomer receives a start message from master, it will spawn several goroutines to run Task.Fn. -// But users can keep some information in the python version, they can't do the same things in boomer. -// Because Task.Fn is a pure function. -type Task struct { - // The weight is used to distribute goroutines over multiple tasks. - Weight int - // Fn is called by the goroutines allocated to this task, in a loop. - Fn func() - Name string -} diff --git a/hrp/pkg/boomer/ulimit.go b/hrp/pkg/boomer/ulimit.go deleted file mode 100644 index bc62a218..00000000 --- a/hrp/pkg/boomer/ulimit.go +++ /dev/null @@ -1,33 +0,0 @@ -//go:build !windows - -package boomer - -import ( - "syscall" - - "github.com/rs/zerolog/log" -) - -// set resource limit -// ulimit -n 10240 -func SetUlimit(limit uint64) { - var rLimit syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) - if err != nil { - log.Error().Err(err).Msg("get ulimit failed") - return - } - log.Info().Uint64("limit", rLimit.Cur).Msg("get current ulimit") - if rLimit.Cur >= limit { - return - } - - rLimit.Cur = limit - rLimit.Max = limit - log.Info().Uint64("limit", rLimit.Cur).Msg("set current ulimit") - err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) - if err != nil { - log.Error().Err(err).Msg("set ulimit failed") - return - } -} diff --git a/hrp/pkg/boomer/ulimit_windows.go b/hrp/pkg/boomer/ulimit_windows.go deleted file mode 100644 index 8641b111..00000000 --- a/hrp/pkg/boomer/ulimit_windows.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build windows - -package boomer - -import ( - "github.com/rs/zerolog/log" -) - -// set resource limit -func SetUlimit(limit uint64) { - log.Warn().Msg("windows does not support setting ulimit") -} diff --git a/hrp/pkg/boomer/utils.go b/hrp/pkg/boomer/utils.go deleted file mode 100644 index 99c2bea4..00000000 --- a/hrp/pkg/boomer/utils.go +++ /dev/null @@ -1,150 +0,0 @@ -package boomer - -import ( - "crypto/md5" - "fmt" - "io" - "math" - "os" - "runtime/pprof" - "strings" - "time" - - "github.com/rs/zerolog/log" - uuid "github.com/satori/go.uuid" - "github.com/shirou/gopsutil/cpu" - "github.com/shirou/gopsutil/mem" - "github.com/shirou/gopsutil/process" -) - -func round(val float64, roundOn float64, places int) (newVal float64) { - var round float64 - pow := math.Pow(10, float64(places)) - digit := pow * val - _, div := math.Modf(digit) - if div >= roundOn { - round = math.Ceil(digit) - } else { - round = math.Floor(digit) - } - newVal = round / pow - return -} - -// genMD5 returns the md5 hash of strings. -func genMD5(slice ...string) string { - h := md5.New() - for _, v := range slice { - io.WriteString(h, v) - } - return fmt.Sprintf("%x", h.Sum(nil)) -} - -// startMemoryProfile starts memory profiling and save the results in file. -func startMemoryProfile(file string, duration time.Duration) (err error) { - f, err := os.Create(file) - if err != nil { - return err - } - - log.Info().Dur("duration", duration).Msg("Start memory profiling") - time.AfterFunc(duration, func() { - err := pprof.WriteHeapProfile(f) - if err != nil { - log.Error().Err(err).Msg("failed to write memory profile") - } - f.Close() - log.Info().Dur("duration", duration).Msg("Stop memory profiling") - }) - return nil -} - -// startCPUProfile starts cpu profiling and save the results in file. -func startCPUProfile(file string, duration time.Duration) (err error) { - f, err := os.Create(file) - if err != nil { - return err - } - - log.Info().Dur("duration", duration).Msg("Start CPU profiling") - err = pprof.StartCPUProfile(f) - if err != nil { - f.Close() - return err - } - - time.AfterFunc(duration, func() { - pprof.StopCPUProfile() - f.Close() - log.Info().Dur("duration", duration).Msg("Stop CPU profiling") - }) - return nil -} - -// generate a random nodeID like locust does, using the same algorithm. -func getNodeID() (nodeID string) { - hostname, _ := os.Hostname() - id := strings.Replace(uuid.NewV4().String(), "-", "", -1) - nodeID = fmt.Sprintf("%s_%s", hostname, id) - return -} - -// GetCurrentPidCPUUsage get current pid CPU usage -func GetCurrentPidCPUUsage() float64 { - currentPid := os.Getpid() - p, err := process.NewProcess(int32(currentPid)) - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - percent, err := p.CPUPercent() - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - return percent -} - -// GetCurrentPidCPUPercent get the percentage of current pid cpu used -func GetCurrentPidCPUPercent() float64 { - currentPid := os.Getpid() - p, err := process.NewProcess(int32(currentPid)) - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - percent, err := p.Percent(time.Second) - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - return percent -} - -// GetCurrentCPUPercent get the percentage of current cpu used -func GetCurrentCPUPercent() float64 { - percent, _ := cpu.Percent(time.Second, false) - return percent[0] -} - -// GetCurrentMemoryPercent get the percentage of current memory used -func GetCurrentMemoryPercent() float64 { - memInfo, _ := mem.VirtualMemory() - return memInfo.UsedPercent -} - -// GetCurrentPidMemoryUsage get current Memory usage -func GetCurrentPidMemoryUsage() float64 { - currentPid := os.Getpid() - p, err := process.NewProcess(int32(currentPid)) - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - percent, err := p.MemoryPercent() - if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("failed to get CPU percent\n")) - return 0.0 - } - return float64(percent) -} diff --git a/hrp/pkg/boomer/utils_test.go b/hrp/pkg/boomer/utils_test.go deleted file mode 100644 index a8448a97..00000000 --- a/hrp/pkg/boomer/utils_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package boomer - -import ( - "os" - "testing" - "time" -) - -func TestRound(t *testing.T) { - if int(round(float64(147.5002), .5, -1)) != 150 { - t.Error("147.5002 should be rounded to 150") - } - - if int(round(float64(3432.5002), .5, -2)) != 3400 { - t.Error("3432.5002 should be rounded to 3400") - } - - roundOne := round(float64(58760.5002), .5, -3) - roundTwo := round(float64(58960.6003), .5, -3) - if roundOne != roundTwo { - t.Error("round(58760.5002) should be equal to round(58960.6003)") - } - - roundOne = round(float64(58360.5002), .5, -3) - roundTwo = round(float64(58460.6003), .5, -3) - if roundOne != roundTwo { - t.Error("round(58360.5002) should be equal to round(58460.6003)") - } - - roundOne = round(float64(58360), .5, -3) - roundTwo = round(float64(58460), .5, -3) - if roundOne != roundTwo { - t.Error("round(58360) should be equal to round(58460)") - } -} - -func TestGenMD5(t *testing.T) { - hashValue := genMD5("Hello", "World!") - if hashValue != "06e0e6637d27b2622ab52022db713ce2" { - t.Error("Expected: 06e0e6637d27b2622ab52022db713ce2, Got: ", hashValue) - } -} - -func TestStartMemoryProfile(t *testing.T) { - if _, err := os.Stat("mem.pprof"); os.IsExist(err) { - os.Remove("mem.pprof") - } - if err := startMemoryProfile("mem.pprof", 2*time.Second); err != nil { - t.Error("Error starting memory profiling") - } - time.Sleep(2100 * time.Millisecond) - if _, err := os.Stat("mem.pprof"); os.IsNotExist(err) { - t.Error("File mem.pprof is not generated") - } else { - os.Remove("mem.pprof") - } -} - -func TestStartCPUProfile(t *testing.T) { - if _, err := os.Stat("cpu.pprof"); os.IsExist(err) { - os.Remove("cpu.pprof") - } - if err := startCPUProfile("cpu.pprof", 2*time.Second); err != nil { - t.Error("Error starting cpu profiling") - } - time.Sleep(2100 * time.Millisecond) - if _, err := os.Stat("cpu.pprof"); os.IsNotExist(err) { - t.Error("File cpu.pprof is not generated") - } else { - os.Remove("cpu.pprof") - } -}