diff --git a/go.mod b/go.mod index 6d8b58cbd9..dc3152a914 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dnscrypt/dnscrypt-proxy -go 1.21 +go 1.23.4 require ( github.com/BurntSushi/toml v1.5.0 @@ -23,7 +23,7 @@ require ( github.com/lifenjoiner/dhcpdns v0.0.7 github.com/miekg/dns v1.1.66 github.com/powerman/check v1.8.0 - github.com/quic-go/quic-go v0.52.0 + github.com/quic-go/quic-go v0.53.0 golang.org/x/crypto v0.39.0 golang.org/x/net v0.41.0 golang.org/x/sys v0.33.0 @@ -32,12 +32,9 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/go-syslog v1.0.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/powerman/deepequal v0.1.0 // indirect diff --git a/go.sum b/go.sum index 2ae2956427..5a7b70c52b 100644 --- a/go.sum +++ b/go.sum @@ -2,30 +2,20 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= -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/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 h1:3T8ZyTDp5QxTx3NU48JVb2u+75xc040fofcBaN+6jPA= github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185/go.mod h1:cFRxtTwTOJkz2x3rQUNCYKWC93yP1VKjR8NUhqFxZNU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -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-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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 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/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/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -40,7 +30,6 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM= github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jedisct1/dlog v0.0.0-20241212093805-3c5fd791b405 h1:6j/0utSiy3KhZSpFJgobk+ME1BIwXeq9jepJaDLW3Yg= github.com/jedisct1/dlog v0.0.0-20241212093805-3c5fd791b405/go.mod h1:OO1HpQNlMCMaPdHPuI00fhChZQZ8npbVTTjMvJUxUqQ= github.com/jedisct1/go-clocksmith v0.0.0-20250224222044-e151f21a353a h1:8z8OvuZGZYGuvTeT5RD80ii6B6LftADl0EQr2z5asCg= @@ -65,10 +54,6 @@ github.com/lifenjoiner/dhcpdns v0.0.7 h1:VJM2aFWHU9V7M5v4UYYNaHhIHZkbdvSI6WGGpq6 github.com/lifenjoiner/dhcpdns v0.0.7/go.mod h1:BixeaGeafYzDIuDCYIUbSOdi4m+TScpzI9cZGYgzgSk= github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= -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= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 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= @@ -79,14 +64,12 @@ github.com/powerman/deepequal v0.1.0 h1:sVwtyTsBuYIvdbLR1O2wzRY63YgPqdGZmk/o80l+ github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA= -github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= +github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI= +github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= @@ -100,7 +83,6 @@ golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= @@ -117,9 +99,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/go-task/slim-sprig/.editorconfig b/vendor/github.com/go-task/slim-sprig/.editorconfig deleted file mode 100644 index b0c95367e7..0000000000 --- a/vendor/github.com/go-task/slim-sprig/.editorconfig +++ /dev/null @@ -1,14 +0,0 @@ -# editorconfig.org - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = tab -indent_size = 8 - -[*.{md,yml,yaml,json}] -indent_style = space -indent_size = 2 diff --git a/vendor/github.com/go-task/slim-sprig/.gitattributes b/vendor/github.com/go-task/slim-sprig/.gitattributes deleted file mode 100644 index 176a458f94..0000000000 --- a/vendor/github.com/go-task/slim-sprig/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto diff --git a/vendor/github.com/go-task/slim-sprig/.gitignore b/vendor/github.com/go-task/slim-sprig/.gitignore deleted file mode 100644 index 5e3002f88f..0000000000 --- a/vendor/github.com/go-task/slim-sprig/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/ -/.glide diff --git a/vendor/github.com/go-task/slim-sprig/CHANGELOG.md b/vendor/github.com/go-task/slim-sprig/CHANGELOG.md deleted file mode 100644 index 61d8ebffc3..0000000000 --- a/vendor/github.com/go-task/slim-sprig/CHANGELOG.md +++ /dev/null @@ -1,364 +0,0 @@ -# Changelog - -## Release 3.2.0 (2020-12-14) - -### Added - -- #211: Added randInt function (thanks @kochurovro) -- #223: Added fromJson and mustFromJson functions (thanks @mholt) -- #242: Added a bcrypt function (thanks @robbiet480) -- #253: Added randBytes function (thanks @MikaelSmith) -- #254: Added dig function for dicts (thanks @nyarly) -- #257: Added regexQuoteMeta for quoting regex metadata (thanks @rheaton) -- #261: Added filepath functions osBase, osDir, osExt, osClean, osIsAbs (thanks @zugl) -- #268: Added and and all functions for testing conditions (thanks @phuslu) -- #181: Added float64 arithmetic addf, add1f, subf, divf, mulf, maxf, and minf - (thanks @andrewmostello) -- #265: Added chunk function to split array into smaller arrays (thanks @karelbilek) -- #270: Extend certificate functions to handle non-RSA keys + add support for - ed25519 keys (thanks @misberner) - -### Changed - -- Removed testing and support for Go 1.12. ed25519 support requires Go 1.13 or newer -- Using semver 3.1.1 and mergo 0.3.11 - -### Fixed - -- #249: Fix htmlDateInZone example (thanks @spawnia) - -NOTE: The dependency github.com/imdario/mergo reverted the breaking change in -0.3.9 via 0.3.10 release. - -## Release 3.1.0 (2020-04-16) - -NOTE: The dependency github.com/imdario/mergo made a behavior change in 0.3.9 -that impacts sprig functionality. Do not use sprig with a version newer than 0.3.8. - -### Added - -- #225: Added support for generating htpasswd hash (thanks @rustycl0ck) -- #224: Added duration filter (thanks @frebib) -- #205: Added `seq` function (thanks @thadc23) - -### Changed - -- #203: Unlambda functions with correct signature (thanks @muesli) -- #236: Updated the license formatting for GitHub display purposes -- #238: Updated package dependency versions. Note, mergo not updated to 0.3.9 - as it causes a breaking change for sprig. That issue is tracked at - https://github.com/imdario/mergo/issues/139 - -### Fixed - -- #229: Fix `seq` example in docs (thanks @kalmant) - -## Release 3.0.2 (2019-12-13) - -### Fixed - -- #220: Updating to semver v3.0.3 to fix issue with <= ranges -- #218: fix typo elyptical->elliptic in ecdsa key description (thanks @laverya) - -## Release 3.0.1 (2019-12-08) - -### Fixed - -- #212: Updated semver fixing broken constraint checking with ^0.0 - -## Release 3.0.0 (2019-10-02) - -### Added - -- #187: Added durationRound function (thanks @yjp20) -- #189: Added numerous template functions that return errors rather than panic (thanks @nrvnrvn) -- #193: Added toRawJson support (thanks @Dean-Coakley) -- #197: Added get support to dicts (thanks @Dean-Coakley) - -### Changed - -- #186: Moving dependency management to Go modules -- #186: Updated semver to v3. This has changes in the way ^ is handled -- #194: Updated documentation on merging and how it copies. Added example using deepCopy -- #196: trunc now supports negative values (thanks @Dean-Coakley) - -## Release 2.22.0 (2019-10-02) - -### Added - -- #173: Added getHostByName function to resolve dns names to ips (thanks @fcgravalos) -- #195: Added deepCopy function for use with dicts - -### Changed - -- Updated merge and mergeOverwrite documentation to explain copying and how to - use deepCopy with it - -## Release 2.21.0 (2019-09-18) - -### Added - -- #122: Added encryptAES/decryptAES functions (thanks @n0madic) -- #128: Added toDecimal support (thanks @Dean-Coakley) -- #169: Added list contcat (thanks @astorath) -- #174: Added deepEqual function (thanks @bonifaido) -- #170: Added url parse and join functions (thanks @astorath) - -### Changed - -- #171: Updated glide config for Google UUID to v1 and to add ranges to semver and testify - -### Fixed - -- #172: Fix semver wildcard example (thanks @piepmatz) -- #175: Fix dateInZone doc example (thanks @s3than) - -## Release 2.20.0 (2019-06-18) - -### Added - -- #164: Adding function to get unix epoch for a time (@mattfarina) -- #166: Adding tests for date_in_zone (@mattfarina) - -### Changed - -- #144: Fix function comments based on best practices from Effective Go (@CodeLingoTeam) -- #150: Handles pointer type for time.Time in "htmlDate" (@mapreal19) -- #161, #157, #160, #153, #158, #156, #155, #159, #152 documentation updates (@badeadan) - -### Fixed - -## Release 2.19.0 (2019-03-02) - -IMPORTANT: This release reverts a change from 2.18.0 - -In the previous release (2.18), we prematurely merged a partial change to the crypto functions that led to creating two sets of crypto functions (I blame @technosophos -- since that's me). This release rolls back that change, and does what was originally intended: It alters the existing crypto functions to use secure random. - -We debated whether this classifies as a change worthy of major revision, but given the proximity to the last release, we have decided that treating 2.18 as a faulty release is the correct course of action. We apologize for any inconvenience. - -### Changed - -- Fix substr panic 35fb796 (Alexey igrychev) -- Remove extra period 1eb7729 (Matthew Lorimor) -- Make random string functions use crypto by default 6ceff26 (Matthew Lorimor) -- README edits/fixes/suggestions 08fe136 (Lauri Apple) - - -## Release 2.18.0 (2019-02-12) - -### Added - -- Added mergeOverwrite function -- cryptographic functions that use secure random (see fe1de12) - -### Changed - -- Improve documentation of regexMatch function, resolves #139 90b89ce (Jan Tagscherer) -- Handle has for nil list 9c10885 (Daniel Cohen) -- Document behaviour of mergeOverwrite fe0dbe9 (Lukas Rieder) -- doc: adds missing documentation. 4b871e6 (Fernandez Ludovic) -- Replace outdated goutils imports 01893d2 (Matthew Lorimor) -- Surface crypto secure random strings from goutils fe1de12 (Matthew Lorimor) -- Handle untyped nil values as paramters to string functions 2b2ec8f (Morten Torkildsen) - -### Fixed - -- Fix dict merge issue and provide mergeOverwrite .dst .src1 to overwrite from src -> dst 4c59c12 (Lukas Rieder) -- Fix substr var names and comments d581f80 (Dean Coakley) -- Fix substr documentation 2737203 (Dean Coakley) - -## Release 2.17.1 (2019-01-03) - -### Fixed - -The 2.17.0 release did not have a version pinned for xstrings, which caused compilation failures when xstrings < 1.2 was used. This adds the correct version string to glide.yaml. - -## Release 2.17.0 (2019-01-03) - -### Added - -- adds alder32sum function and test 6908fc2 (marshallford) -- Added kebabcase function ca331a1 (Ilyes512) - -### Changed - -- Update goutils to 1.1.0 4e1125d (Matt Butcher) - -### Fixed - -- Fix 'has' documentation e3f2a85 (dean-coakley) -- docs(dict): fix typo in pick example dc424f9 (Dustin Specker) -- fixes spelling errors... not sure how that happened 4cf188a (marshallford) - -## Release 2.16.0 (2018-08-13) - -### Added - -- add splitn function fccb0b0 (Helgi Þorbjörnsson) -- Add slice func df28ca7 (gongdo) -- Generate serial number a3bdffd (Cody Coons) -- Extract values of dict with values function df39312 (Lawrence Jones) - -### Changed - -- Modify panic message for list.slice ae38335 (gongdo) -- Minor improvement in code quality - Removed an unreachable piece of code at defaults.go#L26:6 - Resolve formatting issues. 5834241 (Abhishek Kashyap) -- Remove duplicated documentation 1d97af1 (Matthew Fisher) -- Test on go 1.11 49df809 (Helgi Þormar Þorbjörnsson) - -### Fixed - -- Fix file permissions c5f40b5 (gongdo) -- Fix example for buildCustomCert 7779e0d (Tin Lam) - -## Release 2.15.0 (2018-04-02) - -### Added - -- #68 and #69: Add json helpers to docs (thanks @arunvelsriram) -- #66: Add ternary function (thanks @binoculars) -- #67: Allow keys function to take multiple dicts (thanks @binoculars) -- #89: Added sha1sum to crypto function (thanks @benkeil) -- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei) -- #92: Add travis testing for go 1.10 -- #93: Adding appveyor config for windows testing - -### Changed - -- #90: Updating to more recent dependencies -- #73: replace satori/go.uuid with google/uuid (thanks @petterw) - -### Fixed - -- #76: Fixed documentation typos (thanks @Thiht) -- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older - -## Release 2.14.1 (2017-12-01) - -### Fixed - -- #60: Fix typo in function name documentation (thanks @neil-ca-moore) -- #61: Removing line with {{ due to blocking github pages genertion -- #64: Update the list functions to handle int, string, and other slices for compatibility - -## Release 2.14.0 (2017-10-06) - -This new version of Sprig adds a set of functions for generating and working with SSL certificates. - -- `genCA` generates an SSL Certificate Authority -- `genSelfSignedCert` generates an SSL self-signed certificate -- `genSignedCert` generates an SSL certificate and key based on a given CA - -## Release 2.13.0 (2017-09-18) - -This release adds new functions, including: - -- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions -- `floor`, `ceil`, and `round` math functions -- `toDate` converts a string to a date -- `nindent` is just like `indent` but also prepends a new line -- `ago` returns the time from `time.Now` - -### Added - -- #40: Added basic regex functionality (thanks @alanquillin) -- #41: Added ceil floor and round functions (thanks @alanquillin) -- #48: Added toDate function (thanks @andreynering) -- #50: Added nindent function (thanks @binoculars) -- #46: Added ago function (thanks @slayer) - -### Changed - -- #51: Updated godocs to include new string functions (thanks @curtisallen) -- #49: Added ability to merge multiple dicts (thanks @binoculars) - -## Release 2.12.0 (2017-05-17) - -- `snakecase`, `camelcase`, and `shuffle` are three new string functions -- `fail` allows you to bail out of a template render when conditions are not met - -## Release 2.11.0 (2017-05-02) - -- Added `toJson` and `toPrettyJson` -- Added `merge` -- Refactored documentation - -## Release 2.10.0 (2017-03-15) - -- Added `semver` and `semverCompare` for Semantic Versions -- `list` replaces `tuple` -- Fixed issue with `join` -- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` - -## Release 2.9.0 (2017-02-23) - -- Added `splitList` to split a list -- Added crypto functions of `genPrivateKey` and `derivePassword` - -## Release 2.8.0 (2016-12-21) - -- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`) -- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`) - -## Release 2.7.0 (2016-12-01) - -- Added `sha256sum` to generate a hash of an input -- Added functions to convert a numeric or string to `int`, `int64`, `float64` - -## Release 2.6.0 (2016-10-03) - -- Added a `uuidv4` template function for generating UUIDs inside of a template. - -## Release 2.5.0 (2016-08-19) - -- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions -- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`) -- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0 - -## Release 2.4.0 (2016-08-16) - -- Adds two functions: `until` and `untilStep` - -## Release 2.3.0 (2016-06-21) - -- cat: Concatenate strings with whitespace separators. -- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First" -- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos" -- indent: Indent blocks of text in a way that is sensitive to "\n" characters. - -## Release 2.2.0 (2016-04-21) - -- Added a `genPrivateKey` function (Thanks @bacongobbler) - -## Release 2.1.0 (2016-03-30) - -- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`. -- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output. - -## Release 2.0.0 (2016-03-29) - -Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented. - -- `min` complements `max` (formerly `biggest`) -- `empty` indicates that a value is the empty value for its type -- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}` -- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` -- Date formatters have been added for HTML dates (as used in `date` input fields) -- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`). - -## Release 1.2.0 (2016-02-01) - -- Added quote and squote -- Added b32enc and b32dec -- add now takes varargs -- biggest now takes varargs - -## Release 1.1.0 (2015-12-29) - -- Added #4: Added contains function. strings.Contains, but with the arguments - switched to simplify common pipelines. (thanks krancour) -- Added Travis-CI testing support - -## Release 1.0.0 (2015-12-23) - -- Initial release diff --git a/vendor/github.com/go-task/slim-sprig/LICENSE.txt b/vendor/github.com/go-task/slim-sprig/LICENSE.txt deleted file mode 100644 index f311b1eaaa..0000000000 --- a/vendor/github.com/go-task/slim-sprig/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2013-2020 Masterminds - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/go-task/slim-sprig/README.md b/vendor/github.com/go-task/slim-sprig/README.md deleted file mode 100644 index 72579471ff..0000000000 --- a/vendor/github.com/go-task/slim-sprig/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Slim-Sprig: Template functions for Go templates [![GoDoc](https://godoc.org/github.com/go-task/slim-sprig?status.svg)](https://godoc.org/github.com/go-task/slim-sprig) [![Go Report Card](https://goreportcard.com/badge/github.com/go-task/slim-sprig)](https://goreportcard.com/report/github.com/go-task/slim-sprig) - -Slim-Sprig is a fork of [Sprig](https://github.com/Masterminds/sprig), but with -all functions that depend on external (non standard library) or crypto packages -removed. -The reason for this is to make this library more lightweight. Most of these -functions (specially crypto ones) are not needed on most apps, but costs a lot -in terms of binary size and compilation time. - -## Usage - -**Template developers**: Please use Slim-Sprig's [function documentation](https://go-task.github.io/slim-sprig/) for -detailed instructions and code snippets for the >100 template functions available. - -**Go developers**: If you'd like to include Slim-Sprig as a library in your program, -our API documentation is available [at GoDoc.org](http://godoc.org/github.com/go-task/slim-sprig). - -For standard usage, read on. - -### Load the Slim-Sprig library - -To load the Slim-Sprig `FuncMap`: - -```go - -import ( - "html/template" - - "github.com/go-task/slim-sprig" -) - -// This example illustrates that the FuncMap *must* be set before the -// templates themselves are loaded. -tpl := template.Must( - template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html") -) -``` - -### Calling the functions inside of templates - -By convention, all functions are lowercase. This seems to follow the Go -idiom for template functions (as opposed to template methods, which are -TitleCase). For example, this: - -``` -{{ "hello!" | upper | repeat 5 }} -``` - -produces this: - -``` -HELLO!HELLO!HELLO!HELLO!HELLO! -``` - -## Principles Driving Our Function Selection - -We followed these principles to decide which functions to add and how to implement them: - -- Use template functions to build layout. The following - types of operations are within the domain of template functions: - - Formatting - - Layout - - Simple type conversions - - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic) -- Template functions should not return errors unless there is no way to print - a sensible value. For example, converting a string to an integer should not - produce an error if conversion fails. Instead, it should display a default - value. -- Simple math is necessary for grid layouts, pagers, and so on. Complex math - (anything other than arithmetic) should be done outside of templates. -- Template functions only deal with the data passed into them. They never retrieve - data from a source. -- Finally, do not override core Go template functions. diff --git a/vendor/github.com/go-task/slim-sprig/Taskfile.yml b/vendor/github.com/go-task/slim-sprig/Taskfile.yml deleted file mode 100644 index cdcfd223b7..0000000000 --- a/vendor/github.com/go-task/slim-sprig/Taskfile.yml +++ /dev/null @@ -1,12 +0,0 @@ -# https://taskfile.dev - -version: '2' - -tasks: - default: - cmds: - - task: test - - test: - cmds: - - go test -v . diff --git a/vendor/github.com/go-task/slim-sprig/crypto.go b/vendor/github.com/go-task/slim-sprig/crypto.go deleted file mode 100644 index d06e516d49..0000000000 --- a/vendor/github.com/go-task/slim-sprig/crypto.go +++ /dev/null @@ -1,24 +0,0 @@ -package sprig - -import ( - "crypto/sha1" - "crypto/sha256" - "encoding/hex" - "fmt" - "hash/adler32" -) - -func sha256sum(input string) string { - hash := sha256.Sum256([]byte(input)) - return hex.EncodeToString(hash[:]) -} - -func sha1sum(input string) string { - hash := sha1.Sum([]byte(input)) - return hex.EncodeToString(hash[:]) -} - -func adler32sum(input string) string { - hash := adler32.Checksum([]byte(input)) - return fmt.Sprintf("%d", hash) -} diff --git a/vendor/github.com/go-task/slim-sprig/date.go b/vendor/github.com/go-task/slim-sprig/date.go deleted file mode 100644 index ed022ddaca..0000000000 --- a/vendor/github.com/go-task/slim-sprig/date.go +++ /dev/null @@ -1,152 +0,0 @@ -package sprig - -import ( - "strconv" - "time" -) - -// Given a format and a date, format the date string. -// -// Date can be a `time.Time` or an `int, int32, int64`. -// In the later case, it is treated as seconds since UNIX -// epoch. -func date(fmt string, date interface{}) string { - return dateInZone(fmt, date, "Local") -} - -func htmlDate(date interface{}) string { - return dateInZone("2006-01-02", date, "Local") -} - -func htmlDateInZone(date interface{}, zone string) string { - return dateInZone("2006-01-02", date, zone) -} - -func dateInZone(fmt string, date interface{}, zone string) string { - var t time.Time - switch date := date.(type) { - default: - t = time.Now() - case time.Time: - t = date - case *time.Time: - t = *date - case int64: - t = time.Unix(date, 0) - case int: - t = time.Unix(int64(date), 0) - case int32: - t = time.Unix(int64(date), 0) - } - - loc, err := time.LoadLocation(zone) - if err != nil { - loc, _ = time.LoadLocation("UTC") - } - - return t.In(loc).Format(fmt) -} - -func dateModify(fmt string, date time.Time) time.Time { - d, err := time.ParseDuration(fmt) - if err != nil { - return date - } - return date.Add(d) -} - -func mustDateModify(fmt string, date time.Time) (time.Time, error) { - d, err := time.ParseDuration(fmt) - if err != nil { - return time.Time{}, err - } - return date.Add(d), nil -} - -func dateAgo(date interface{}) string { - var t time.Time - - switch date := date.(type) { - default: - t = time.Now() - case time.Time: - t = date - case int64: - t = time.Unix(date, 0) - case int: - t = time.Unix(int64(date), 0) - } - // Drop resolution to seconds - duration := time.Since(t).Round(time.Second) - return duration.String() -} - -func duration(sec interface{}) string { - var n int64 - switch value := sec.(type) { - default: - n = 0 - case string: - n, _ = strconv.ParseInt(value, 10, 64) - case int64: - n = value - } - return (time.Duration(n) * time.Second).String() -} - -func durationRound(duration interface{}) string { - var d time.Duration - switch duration := duration.(type) { - default: - d = 0 - case string: - d, _ = time.ParseDuration(duration) - case int64: - d = time.Duration(duration) - case time.Time: - d = time.Since(duration) - } - - u := uint64(d) - neg := d < 0 - if neg { - u = -u - } - - var ( - year = uint64(time.Hour) * 24 * 365 - month = uint64(time.Hour) * 24 * 30 - day = uint64(time.Hour) * 24 - hour = uint64(time.Hour) - minute = uint64(time.Minute) - second = uint64(time.Second) - ) - switch { - case u > year: - return strconv.FormatUint(u/year, 10) + "y" - case u > month: - return strconv.FormatUint(u/month, 10) + "mo" - case u > day: - return strconv.FormatUint(u/day, 10) + "d" - case u > hour: - return strconv.FormatUint(u/hour, 10) + "h" - case u > minute: - return strconv.FormatUint(u/minute, 10) + "m" - case u > second: - return strconv.FormatUint(u/second, 10) + "s" - } - return "0s" -} - -func toDate(fmt, str string) time.Time { - t, _ := time.ParseInLocation(fmt, str, time.Local) - return t -} - -func mustToDate(fmt, str string) (time.Time, error) { - return time.ParseInLocation(fmt, str, time.Local) -} - -func unixEpoch(date time.Time) string { - return strconv.FormatInt(date.Unix(), 10) -} diff --git a/vendor/github.com/go-task/slim-sprig/defaults.go b/vendor/github.com/go-task/slim-sprig/defaults.go deleted file mode 100644 index b9f979666d..0000000000 --- a/vendor/github.com/go-task/slim-sprig/defaults.go +++ /dev/null @@ -1,163 +0,0 @@ -package sprig - -import ( - "bytes" - "encoding/json" - "math/rand" - "reflect" - "strings" - "time" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -// dfault checks whether `given` is set, and returns default if not set. -// -// This returns `d` if `given` appears not to be set, and `given` otherwise. -// -// For numeric types 0 is unset. -// For strings, maps, arrays, and slices, len() = 0 is considered unset. -// For bool, false is unset. -// Structs are never considered unset. -// -// For everything else, including pointers, a nil value is unset. -func dfault(d interface{}, given ...interface{}) interface{} { - - if empty(given) || empty(given[0]) { - return d - } - return given[0] -} - -// empty returns true if the given value has the zero value for its type. -func empty(given interface{}) bool { - g := reflect.ValueOf(given) - if !g.IsValid() { - return true - } - - // Basically adapted from text/template.isTrue - switch g.Kind() { - default: - return g.IsNil() - case reflect.Array, reflect.Slice, reflect.Map, reflect.String: - return g.Len() == 0 - case reflect.Bool: - return !g.Bool() - case reflect.Complex64, reflect.Complex128: - return g.Complex() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return g.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return g.Uint() == 0 - case reflect.Float32, reflect.Float64: - return g.Float() == 0 - case reflect.Struct: - return false - } -} - -// coalesce returns the first non-empty value. -func coalesce(v ...interface{}) interface{} { - for _, val := range v { - if !empty(val) { - return val - } - } - return nil -} - -// all returns true if empty(x) is false for all values x in the list. -// If the list is empty, return true. -func all(v ...interface{}) bool { - for _, val := range v { - if empty(val) { - return false - } - } - return true -} - -// any returns true if empty(x) is false for any x in the list. -// If the list is empty, return false. -func any(v ...interface{}) bool { - for _, val := range v { - if !empty(val) { - return true - } - } - return false -} - -// fromJson decodes JSON into a structured value, ignoring errors. -func fromJson(v string) interface{} { - output, _ := mustFromJson(v) - return output -} - -// mustFromJson decodes JSON into a structured value, returning errors. -func mustFromJson(v string) (interface{}, error) { - var output interface{} - err := json.Unmarshal([]byte(v), &output) - return output, err -} - -// toJson encodes an item into a JSON string -func toJson(v interface{}) string { - output, _ := json.Marshal(v) - return string(output) -} - -func mustToJson(v interface{}) (string, error) { - output, err := json.Marshal(v) - if err != nil { - return "", err - } - return string(output), nil -} - -// toPrettyJson encodes an item into a pretty (indented) JSON string -func toPrettyJson(v interface{}) string { - output, _ := json.MarshalIndent(v, "", " ") - return string(output) -} - -func mustToPrettyJson(v interface{}) (string, error) { - output, err := json.MarshalIndent(v, "", " ") - if err != nil { - return "", err - } - return string(output), nil -} - -// toRawJson encodes an item into a JSON string with no escaping of HTML characters. -func toRawJson(v interface{}) string { - output, err := mustToRawJson(v) - if err != nil { - panic(err) - } - return string(output) -} - -// mustToRawJson encodes an item into a JSON string with no escaping of HTML characters. -func mustToRawJson(v interface{}) (string, error) { - buf := new(bytes.Buffer) - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - err := enc.Encode(&v) - if err != nil { - return "", err - } - return strings.TrimSuffix(buf.String(), "\n"), nil -} - -// ternary returns the first value if the last value is true, otherwise returns the second value. -func ternary(vt interface{}, vf interface{}, v bool) interface{} { - if v { - return vt - } - - return vf -} diff --git a/vendor/github.com/go-task/slim-sprig/dict.go b/vendor/github.com/go-task/slim-sprig/dict.go deleted file mode 100644 index 77ebc61b18..0000000000 --- a/vendor/github.com/go-task/slim-sprig/dict.go +++ /dev/null @@ -1,118 +0,0 @@ -package sprig - -func get(d map[string]interface{}, key string) interface{} { - if val, ok := d[key]; ok { - return val - } - return "" -} - -func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} { - d[key] = value - return d -} - -func unset(d map[string]interface{}, key string) map[string]interface{} { - delete(d, key) - return d -} - -func hasKey(d map[string]interface{}, key string) bool { - _, ok := d[key] - return ok -} - -func pluck(key string, d ...map[string]interface{}) []interface{} { - res := []interface{}{} - for _, dict := range d { - if val, ok := dict[key]; ok { - res = append(res, val) - } - } - return res -} - -func keys(dicts ...map[string]interface{}) []string { - k := []string{} - for _, dict := range dicts { - for key := range dict { - k = append(k, key) - } - } - return k -} - -func pick(dict map[string]interface{}, keys ...string) map[string]interface{} { - res := map[string]interface{}{} - for _, k := range keys { - if v, ok := dict[k]; ok { - res[k] = v - } - } - return res -} - -func omit(dict map[string]interface{}, keys ...string) map[string]interface{} { - res := map[string]interface{}{} - - omit := make(map[string]bool, len(keys)) - for _, k := range keys { - omit[k] = true - } - - for k, v := range dict { - if _, ok := omit[k]; !ok { - res[k] = v - } - } - return res -} - -func dict(v ...interface{}) map[string]interface{} { - dict := map[string]interface{}{} - lenv := len(v) - for i := 0; i < lenv; i += 2 { - key := strval(v[i]) - if i+1 >= lenv { - dict[key] = "" - continue - } - dict[key] = v[i+1] - } - return dict -} - -func values(dict map[string]interface{}) []interface{} { - values := []interface{}{} - for _, value := range dict { - values = append(values, value) - } - - return values -} - -func dig(ps ...interface{}) (interface{}, error) { - if len(ps) < 3 { - panic("dig needs at least three arguments") - } - dict := ps[len(ps)-1].(map[string]interface{}) - def := ps[len(ps)-2] - ks := make([]string, len(ps)-2) - for i := 0; i < len(ks); i++ { - ks[i] = ps[i].(string) - } - - return digFromDict(dict, def, ks) -} - -func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (interface{}, error) { - k, ns := ks[0], ks[1:len(ks)] - step, has := dict[k] - if !has { - return d, nil - } - if len(ns) == 0 { - return step, nil - } - return digFromDict(step.(map[string]interface{}), d, ns) -} diff --git a/vendor/github.com/go-task/slim-sprig/doc.go b/vendor/github.com/go-task/slim-sprig/doc.go deleted file mode 100644 index aabb9d4489..0000000000 --- a/vendor/github.com/go-task/slim-sprig/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Package sprig provides template functions for Go. - -This package contains a number of utility functions for working with data -inside of Go `html/template` and `text/template` files. - -To add these functions, use the `template.Funcs()` method: - - t := templates.New("foo").Funcs(sprig.FuncMap()) - -Note that you should add the function map before you parse any template files. - - In several cases, Sprig reverses the order of arguments from the way they - appear in the standard library. This is to make it easier to pipe - arguments into functions. - -See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions. -*/ -package sprig diff --git a/vendor/github.com/go-task/slim-sprig/functions.go b/vendor/github.com/go-task/slim-sprig/functions.go deleted file mode 100644 index 5ea74f8993..0000000000 --- a/vendor/github.com/go-task/slim-sprig/functions.go +++ /dev/null @@ -1,317 +0,0 @@ -package sprig - -import ( - "errors" - "html/template" - "math/rand" - "os" - "path" - "path/filepath" - "reflect" - "strconv" - "strings" - ttemplate "text/template" - "time" -) - -// FuncMap produces the function map. -// -// Use this to pass the functions into the template engine: -// -// tpl := template.New("foo").Funcs(sprig.FuncMap())) -// -func FuncMap() template.FuncMap { - return HtmlFuncMap() -} - -// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions. -func HermeticTxtFuncMap() ttemplate.FuncMap { - r := TxtFuncMap() - for _, name := range nonhermeticFunctions { - delete(r, name) - } - return r -} - -// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions. -func HermeticHtmlFuncMap() template.FuncMap { - r := HtmlFuncMap() - for _, name := range nonhermeticFunctions { - delete(r, name) - } - return r -} - -// TxtFuncMap returns a 'text/template'.FuncMap -func TxtFuncMap() ttemplate.FuncMap { - return ttemplate.FuncMap(GenericFuncMap()) -} - -// HtmlFuncMap returns an 'html/template'.Funcmap -func HtmlFuncMap() template.FuncMap { - return template.FuncMap(GenericFuncMap()) -} - -// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}. -func GenericFuncMap() map[string]interface{} { - gfm := make(map[string]interface{}, len(genericMap)) - for k, v := range genericMap { - gfm[k] = v - } - return gfm -} - -// These functions are not guaranteed to evaluate to the same result for given input, because they -// refer to the environment or global state. -var nonhermeticFunctions = []string{ - // Date functions - "date", - "date_in_zone", - "date_modify", - "now", - "htmlDate", - "htmlDateInZone", - "dateInZone", - "dateModify", - - // Strings - "randAlphaNum", - "randAlpha", - "randAscii", - "randNumeric", - "randBytes", - "uuidv4", - - // OS - "env", - "expandenv", - - // Network - "getHostByName", -} - -var genericMap = map[string]interface{}{ - "hello": func() string { return "Hello!" }, - - // Date functions - "ago": dateAgo, - "date": date, - "date_in_zone": dateInZone, - "date_modify": dateModify, - "dateInZone": dateInZone, - "dateModify": dateModify, - "duration": duration, - "durationRound": durationRound, - "htmlDate": htmlDate, - "htmlDateInZone": htmlDateInZone, - "must_date_modify": mustDateModify, - "mustDateModify": mustDateModify, - "mustToDate": mustToDate, - "now": time.Now, - "toDate": toDate, - "unixEpoch": unixEpoch, - - // Strings - "trunc": trunc, - "trim": strings.TrimSpace, - "upper": strings.ToUpper, - "lower": strings.ToLower, - "title": strings.Title, - "substr": substring, - // Switch order so that "foo" | repeat 5 - "repeat": func(count int, str string) string { return strings.Repeat(str, count) }, - // Deprecated: Use trimAll. - "trimall": func(a, b string) string { return strings.Trim(b, a) }, - // Switch order so that "$foo" | trimall "$" - "trimAll": func(a, b string) string { return strings.Trim(b, a) }, - "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) }, - "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) }, - // Switch order so that "foobar" | contains "foo" - "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, - "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, - "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) }, - "quote": quote, - "squote": squote, - "cat": cat, - "indent": indent, - "nindent": nindent, - "replace": replace, - "plural": plural, - "sha1sum": sha1sum, - "sha256sum": sha256sum, - "adler32sum": adler32sum, - "toString": strval, - - // Wrap Atoi to stop errors. - "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i }, - "int64": toInt64, - "int": toInt, - "float64": toFloat64, - "seq": seq, - "toDecimal": toDecimal, - - //"gt": func(a, b int) bool {return a > b}, - //"gte": func(a, b int) bool {return a >= b}, - //"lt": func(a, b int) bool {return a < b}, - //"lte": func(a, b int) bool {return a <= b}, - - // split "/" foo/bar returns map[int]string{0: foo, 1: bar} - "split": split, - "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, - // splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu} - "splitn": splitn, - "toStrings": strslice, - - "until": until, - "untilStep": untilStep, - - // VERY basic arithmetic. - "add1": func(i interface{}) int64 { return toInt64(i) + 1 }, - "add": func(i ...interface{}) int64 { - var a int64 = 0 - for _, b := range i { - a += toInt64(b) - } - return a - }, - "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) }, - "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) }, - "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) }, - "mul": func(a interface{}, v ...interface{}) int64 { - val := toInt64(a) - for _, b := range v { - val = val * toInt64(b) - } - return val - }, - "randInt": func(min, max int) int { return rand.Intn(max-min) + min }, - "biggest": max, - "max": max, - "min": min, - "maxf": maxf, - "minf": minf, - "ceil": ceil, - "floor": floor, - "round": round, - - // string slices. Note that we reverse the order b/c that's better - // for template processing. - "join": join, - "sortAlpha": sortAlpha, - - // Defaults - "default": dfault, - "empty": empty, - "coalesce": coalesce, - "all": all, - "any": any, - "compact": compact, - "mustCompact": mustCompact, - "fromJson": fromJson, - "toJson": toJson, - "toPrettyJson": toPrettyJson, - "toRawJson": toRawJson, - "mustFromJson": mustFromJson, - "mustToJson": mustToJson, - "mustToPrettyJson": mustToPrettyJson, - "mustToRawJson": mustToRawJson, - "ternary": ternary, - - // Reflection - "typeOf": typeOf, - "typeIs": typeIs, - "typeIsLike": typeIsLike, - "kindOf": kindOf, - "kindIs": kindIs, - "deepEqual": reflect.DeepEqual, - - // OS: - "env": os.Getenv, - "expandenv": os.ExpandEnv, - - // Network: - "getHostByName": getHostByName, - - // Paths: - "base": path.Base, - "dir": path.Dir, - "clean": path.Clean, - "ext": path.Ext, - "isAbs": path.IsAbs, - - // Filepaths: - "osBase": filepath.Base, - "osClean": filepath.Clean, - "osDir": filepath.Dir, - "osExt": filepath.Ext, - "osIsAbs": filepath.IsAbs, - - // Encoding: - "b64enc": base64encode, - "b64dec": base64decode, - "b32enc": base32encode, - "b32dec": base32decode, - - // Data Structures: - "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable. - "list": list, - "dict": dict, - "get": get, - "set": set, - "unset": unset, - "hasKey": hasKey, - "pluck": pluck, - "keys": keys, - "pick": pick, - "omit": omit, - "values": values, - - "append": push, "push": push, - "mustAppend": mustPush, "mustPush": mustPush, - "prepend": prepend, - "mustPrepend": mustPrepend, - "first": first, - "mustFirst": mustFirst, - "rest": rest, - "mustRest": mustRest, - "last": last, - "mustLast": mustLast, - "initial": initial, - "mustInitial": mustInitial, - "reverse": reverse, - "mustReverse": mustReverse, - "uniq": uniq, - "mustUniq": mustUniq, - "without": without, - "mustWithout": mustWithout, - "has": has, - "mustHas": mustHas, - "slice": slice, - "mustSlice": mustSlice, - "concat": concat, - "dig": dig, - "chunk": chunk, - "mustChunk": mustChunk, - - // Flow Control: - "fail": func(msg string) (string, error) { return "", errors.New(msg) }, - - // Regex - "regexMatch": regexMatch, - "mustRegexMatch": mustRegexMatch, - "regexFindAll": regexFindAll, - "mustRegexFindAll": mustRegexFindAll, - "regexFind": regexFind, - "mustRegexFind": mustRegexFind, - "regexReplaceAll": regexReplaceAll, - "mustRegexReplaceAll": mustRegexReplaceAll, - "regexReplaceAllLiteral": regexReplaceAllLiteral, - "mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral, - "regexSplit": regexSplit, - "mustRegexSplit": mustRegexSplit, - "regexQuoteMeta": regexQuoteMeta, - - // URLs: - "urlParse": urlParse, - "urlJoin": urlJoin, -} diff --git a/vendor/github.com/go-task/slim-sprig/list.go b/vendor/github.com/go-task/slim-sprig/list.go deleted file mode 100644 index ca0fbb7893..0000000000 --- a/vendor/github.com/go-task/slim-sprig/list.go +++ /dev/null @@ -1,464 +0,0 @@ -package sprig - -import ( - "fmt" - "math" - "reflect" - "sort" -) - -// Reflection is used in these functions so that slices and arrays of strings, -// ints, and other types not implementing []interface{} can be worked with. -// For example, this is useful if you need to work on the output of regexs. - -func list(v ...interface{}) []interface{} { - return v -} - -func push(list interface{}, v interface{}) []interface{} { - l, err := mustPush(list, v) - if err != nil { - panic(err) - } - - return l -} - -func mustPush(list interface{}, v interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[i] = l2.Index(i).Interface() - } - - return append(nl, v), nil - - default: - return nil, fmt.Errorf("Cannot push on type %s", tp) - } -} - -func prepend(list interface{}, v interface{}) []interface{} { - l, err := mustPrepend(list, v) - if err != nil { - panic(err) - } - - return l -} - -func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) { - //return append([]interface{}{v}, list...) - - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[i] = l2.Index(i).Interface() - } - - return append([]interface{}{v}, nl...), nil - - default: - return nil, fmt.Errorf("Cannot prepend on type %s", tp) - } -} - -func chunk(size int, list interface{}) [][]interface{} { - l, err := mustChunk(size, list) - if err != nil { - panic(err) - } - - return l -} - -func mustChunk(size int, list interface{}) ([][]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - - cs := int(math.Floor(float64(l-1)/float64(size)) + 1) - nl := make([][]interface{}, cs) - - for i := 0; i < cs; i++ { - clen := size - if i == cs-1 { - clen = int(math.Floor(math.Mod(float64(l), float64(size)))) - if clen == 0 { - clen = size - } - } - - nl[i] = make([]interface{}, clen) - - for j := 0; j < clen; j++ { - ix := i*size + j - nl[i][j] = l2.Index(ix).Interface() - } - } - - return nl, nil - - default: - return nil, fmt.Errorf("Cannot chunk type %s", tp) - } -} - -func last(list interface{}) interface{} { - l, err := mustLast(list) - if err != nil { - panic(err) - } - - return l -} - -func mustLast(list interface{}) (interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil, nil - } - - return l2.Index(l - 1).Interface(), nil - default: - return nil, fmt.Errorf("Cannot find last on type %s", tp) - } -} - -func first(list interface{}) interface{} { - l, err := mustFirst(list) - if err != nil { - panic(err) - } - - return l -} - -func mustFirst(list interface{}) (interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil, nil - } - - return l2.Index(0).Interface(), nil - default: - return nil, fmt.Errorf("Cannot find first on type %s", tp) - } -} - -func rest(list interface{}) []interface{} { - l, err := mustRest(list) - if err != nil { - panic(err) - } - - return l -} - -func mustRest(list interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil, nil - } - - nl := make([]interface{}, l-1) - for i := 1; i < l; i++ { - nl[i-1] = l2.Index(i).Interface() - } - - return nl, nil - default: - return nil, fmt.Errorf("Cannot find rest on type %s", tp) - } -} - -func initial(list interface{}) []interface{} { - l, err := mustInitial(list) - if err != nil { - panic(err) - } - - return l -} - -func mustInitial(list interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil, nil - } - - nl := make([]interface{}, l-1) - for i := 0; i < l-1; i++ { - nl[i] = l2.Index(i).Interface() - } - - return nl, nil - default: - return nil, fmt.Errorf("Cannot find initial on type %s", tp) - } -} - -func sortAlpha(list interface{}) []string { - k := reflect.Indirect(reflect.ValueOf(list)).Kind() - switch k { - case reflect.Slice, reflect.Array: - a := strslice(list) - s := sort.StringSlice(a) - s.Sort() - return s - } - return []string{strval(list)} -} - -func reverse(v interface{}) []interface{} { - l, err := mustReverse(v) - if err != nil { - panic(err) - } - - return l -} - -func mustReverse(v interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(v).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(v) - - l := l2.Len() - // We do not sort in place because the incoming array should not be altered. - nl := make([]interface{}, l) - for i := 0; i < l; i++ { - nl[l-i-1] = l2.Index(i).Interface() - } - - return nl, nil - default: - return nil, fmt.Errorf("Cannot find reverse on type %s", tp) - } -} - -func compact(list interface{}) []interface{} { - l, err := mustCompact(list) - if err != nil { - panic(err) - } - - return l -} - -func mustCompact(list interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - nl := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !empty(item) { - nl = append(nl, item) - } - } - - return nl, nil - default: - return nil, fmt.Errorf("Cannot compact on type %s", tp) - } -} - -func uniq(list interface{}) []interface{} { - l, err := mustUniq(list) - if err != nil { - panic(err) - } - - return l -} - -func mustUniq(list interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - dest := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !inList(dest, item) { - dest = append(dest, item) - } - } - - return dest, nil - default: - return nil, fmt.Errorf("Cannot find uniq on type %s", tp) - } -} - -func inList(haystack []interface{}, needle interface{}) bool { - for _, h := range haystack { - if reflect.DeepEqual(needle, h) { - return true - } - } - return false -} - -func without(list interface{}, omit ...interface{}) []interface{} { - l, err := mustWithout(list, omit...) - if err != nil { - panic(err) - } - - return l -} - -func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - res := []interface{}{} - var item interface{} - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if !inList(omit, item) { - res = append(res, item) - } - } - - return res, nil - default: - return nil, fmt.Errorf("Cannot find without on type %s", tp) - } -} - -func has(needle interface{}, haystack interface{}) bool { - l, err := mustHas(needle, haystack) - if err != nil { - panic(err) - } - - return l -} - -func mustHas(needle interface{}, haystack interface{}) (bool, error) { - if haystack == nil { - return false, nil - } - tp := reflect.TypeOf(haystack).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(haystack) - var item interface{} - l := l2.Len() - for i := 0; i < l; i++ { - item = l2.Index(i).Interface() - if reflect.DeepEqual(needle, item) { - return true, nil - } - } - - return false, nil - default: - return false, fmt.Errorf("Cannot find has on type %s", tp) - } -} - -// $list := [1, 2, 3, 4, 5] -// slice $list -> list[0:5] = list[:] -// slice $list 0 3 -> list[0:3] = list[:3] -// slice $list 3 5 -> list[3:5] -// slice $list 3 -> list[3:5] = list[3:] -func slice(list interface{}, indices ...interface{}) interface{} { - l, err := mustSlice(list, indices...) - if err != nil { - panic(err) - } - - return l -} - -func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - - l := l2.Len() - if l == 0 { - return nil, nil - } - - var start, end int - if len(indices) > 0 { - start = toInt(indices[0]) - } - if len(indices) < 2 { - end = l - } else { - end = toInt(indices[1]) - } - - return l2.Slice(start, end).Interface(), nil - default: - return nil, fmt.Errorf("list should be type of slice or array but %s", tp) - } -} - -func concat(lists ...interface{}) interface{} { - var res []interface{} - for _, list := range lists { - tp := reflect.TypeOf(list).Kind() - switch tp { - case reflect.Slice, reflect.Array: - l2 := reflect.ValueOf(list) - for i := 0; i < l2.Len(); i++ { - res = append(res, l2.Index(i).Interface()) - } - default: - panic(fmt.Sprintf("Cannot concat type %s as list", tp)) - } - } - return res -} diff --git a/vendor/github.com/go-task/slim-sprig/network.go b/vendor/github.com/go-task/slim-sprig/network.go deleted file mode 100644 index 108d78a946..0000000000 --- a/vendor/github.com/go-task/slim-sprig/network.go +++ /dev/null @@ -1,12 +0,0 @@ -package sprig - -import ( - "math/rand" - "net" -) - -func getHostByName(name string) string { - addrs, _ := net.LookupHost(name) - //TODO: add error handing when release v3 comes out - return addrs[rand.Intn(len(addrs))] -} diff --git a/vendor/github.com/go-task/slim-sprig/numeric.go b/vendor/github.com/go-task/slim-sprig/numeric.go deleted file mode 100644 index 98cbb37a19..0000000000 --- a/vendor/github.com/go-task/slim-sprig/numeric.go +++ /dev/null @@ -1,228 +0,0 @@ -package sprig - -import ( - "fmt" - "math" - "reflect" - "strconv" - "strings" -) - -// toFloat64 converts 64-bit floats -func toFloat64(v interface{}) float64 { - if str, ok := v.(string); ok { - iv, err := strconv.ParseFloat(str, 64) - if err != nil { - return 0 - } - return iv - } - - val := reflect.Indirect(reflect.ValueOf(v)) - switch val.Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return float64(val.Int()) - case reflect.Uint8, reflect.Uint16, reflect.Uint32: - return float64(val.Uint()) - case reflect.Uint, reflect.Uint64: - return float64(val.Uint()) - case reflect.Float32, reflect.Float64: - return val.Float() - case reflect.Bool: - if val.Bool() { - return 1 - } - return 0 - default: - return 0 - } -} - -func toInt(v interface{}) int { - //It's not optimal. Bud I don't want duplicate toInt64 code. - return int(toInt64(v)) -} - -// toInt64 converts integer types to 64-bit integers -func toInt64(v interface{}) int64 { - if str, ok := v.(string); ok { - iv, err := strconv.ParseInt(str, 10, 64) - if err != nil { - return 0 - } - return iv - } - - val := reflect.Indirect(reflect.ValueOf(v)) - switch val.Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return val.Int() - case reflect.Uint8, reflect.Uint16, reflect.Uint32: - return int64(val.Uint()) - case reflect.Uint, reflect.Uint64: - tv := val.Uint() - if tv <= math.MaxInt64 { - return int64(tv) - } - // TODO: What is the sensible thing to do here? - return math.MaxInt64 - case reflect.Float32, reflect.Float64: - return int64(val.Float()) - case reflect.Bool: - if val.Bool() { - return 1 - } - return 0 - default: - return 0 - } -} - -func max(a interface{}, i ...interface{}) int64 { - aa := toInt64(a) - for _, b := range i { - bb := toInt64(b) - if bb > aa { - aa = bb - } - } - return aa -} - -func maxf(a interface{}, i ...interface{}) float64 { - aa := toFloat64(a) - for _, b := range i { - bb := toFloat64(b) - aa = math.Max(aa, bb) - } - return aa -} - -func min(a interface{}, i ...interface{}) int64 { - aa := toInt64(a) - for _, b := range i { - bb := toInt64(b) - if bb < aa { - aa = bb - } - } - return aa -} - -func minf(a interface{}, i ...interface{}) float64 { - aa := toFloat64(a) - for _, b := range i { - bb := toFloat64(b) - aa = math.Min(aa, bb) - } - return aa -} - -func until(count int) []int { - step := 1 - if count < 0 { - step = -1 - } - return untilStep(0, count, step) -} - -func untilStep(start, stop, step int) []int { - v := []int{} - - if stop < start { - if step >= 0 { - return v - } - for i := start; i > stop; i += step { - v = append(v, i) - } - return v - } - - if step <= 0 { - return v - } - for i := start; i < stop; i += step { - v = append(v, i) - } - return v -} - -func floor(a interface{}) float64 { - aa := toFloat64(a) - return math.Floor(aa) -} - -func ceil(a interface{}) float64 { - aa := toFloat64(a) - return math.Ceil(aa) -} - -func round(a interface{}, p int, rOpt ...float64) float64 { - roundOn := .5 - if len(rOpt) > 0 { - roundOn = rOpt[0] - } - val := toFloat64(a) - places := toFloat64(p) - - var round float64 - pow := math.Pow(10, places) - digit := pow * val - _, div := math.Modf(digit) - if div >= roundOn { - round = math.Ceil(digit) - } else { - round = math.Floor(digit) - } - return round / pow -} - -// converts unix octal to decimal -func toDecimal(v interface{}) int64 { - result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64) - if err != nil { - return 0 - } - return result -} - -func seq(params ...int) string { - increment := 1 - switch len(params) { - case 0: - return "" - case 1: - start := 1 - end := params[0] - if end < start { - increment = -1 - } - return intArrayToString(untilStep(start, end+increment, increment), " ") - case 3: - start := params[0] - end := params[2] - step := params[1] - if end < start { - increment = -1 - if step > 0 { - return "" - } - } - return intArrayToString(untilStep(start, end+increment, step), " ") - case 2: - start := params[0] - end := params[1] - step := 1 - if end < start { - step = -1 - } - return intArrayToString(untilStep(start, end+step, step), " ") - default: - return "" - } -} - -func intArrayToString(slice []int, delimeter string) string { - return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]") -} diff --git a/vendor/github.com/go-task/slim-sprig/reflect.go b/vendor/github.com/go-task/slim-sprig/reflect.go deleted file mode 100644 index 8a65c132f0..0000000000 --- a/vendor/github.com/go-task/slim-sprig/reflect.go +++ /dev/null @@ -1,28 +0,0 @@ -package sprig - -import ( - "fmt" - "reflect" -) - -// typeIs returns true if the src is the type named in target. -func typeIs(target string, src interface{}) bool { - return target == typeOf(src) -} - -func typeIsLike(target string, src interface{}) bool { - t := typeOf(src) - return target == t || "*"+target == t -} - -func typeOf(src interface{}) string { - return fmt.Sprintf("%T", src) -} - -func kindIs(target string, src interface{}) bool { - return target == kindOf(src) -} - -func kindOf(src interface{}) string { - return reflect.ValueOf(src).Kind().String() -} diff --git a/vendor/github.com/go-task/slim-sprig/regex.go b/vendor/github.com/go-task/slim-sprig/regex.go deleted file mode 100644 index fab5510189..0000000000 --- a/vendor/github.com/go-task/slim-sprig/regex.go +++ /dev/null @@ -1,83 +0,0 @@ -package sprig - -import ( - "regexp" -) - -func regexMatch(regex string, s string) bool { - match, _ := regexp.MatchString(regex, s) - return match -} - -func mustRegexMatch(regex string, s string) (bool, error) { - return regexp.MatchString(regex, s) -} - -func regexFindAll(regex string, s string, n int) []string { - r := regexp.MustCompile(regex) - return r.FindAllString(s, n) -} - -func mustRegexFindAll(regex string, s string, n int) ([]string, error) { - r, err := regexp.Compile(regex) - if err != nil { - return []string{}, err - } - return r.FindAllString(s, n), nil -} - -func regexFind(regex string, s string) string { - r := regexp.MustCompile(regex) - return r.FindString(s) -} - -func mustRegexFind(regex string, s string) (string, error) { - r, err := regexp.Compile(regex) - if err != nil { - return "", err - } - return r.FindString(s), nil -} - -func regexReplaceAll(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllString(s, repl) -} - -func mustRegexReplaceAll(regex string, s string, repl string) (string, error) { - r, err := regexp.Compile(regex) - if err != nil { - return "", err - } - return r.ReplaceAllString(s, repl), nil -} - -func regexReplaceAllLiteral(regex string, s string, repl string) string { - r := regexp.MustCompile(regex) - return r.ReplaceAllLiteralString(s, repl) -} - -func mustRegexReplaceAllLiteral(regex string, s string, repl string) (string, error) { - r, err := regexp.Compile(regex) - if err != nil { - return "", err - } - return r.ReplaceAllLiteralString(s, repl), nil -} - -func regexSplit(regex string, s string, n int) []string { - r := regexp.MustCompile(regex) - return r.Split(s, n) -} - -func mustRegexSplit(regex string, s string, n int) ([]string, error) { - r, err := regexp.Compile(regex) - if err != nil { - return []string{}, err - } - return r.Split(s, n), nil -} - -func regexQuoteMeta(s string) string { - return regexp.QuoteMeta(s) -} diff --git a/vendor/github.com/go-task/slim-sprig/strings.go b/vendor/github.com/go-task/slim-sprig/strings.go deleted file mode 100644 index 3c62d6b6f2..0000000000 --- a/vendor/github.com/go-task/slim-sprig/strings.go +++ /dev/null @@ -1,189 +0,0 @@ -package sprig - -import ( - "encoding/base32" - "encoding/base64" - "fmt" - "reflect" - "strconv" - "strings" -) - -func base64encode(v string) string { - return base64.StdEncoding.EncodeToString([]byte(v)) -} - -func base64decode(v string) string { - data, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return err.Error() - } - return string(data) -} - -func base32encode(v string) string { - return base32.StdEncoding.EncodeToString([]byte(v)) -} - -func base32decode(v string) string { - data, err := base32.StdEncoding.DecodeString(v) - if err != nil { - return err.Error() - } - return string(data) -} - -func quote(str ...interface{}) string { - out := make([]string, 0, len(str)) - for _, s := range str { - if s != nil { - out = append(out, fmt.Sprintf("%q", strval(s))) - } - } - return strings.Join(out, " ") -} - -func squote(str ...interface{}) string { - out := make([]string, 0, len(str)) - for _, s := range str { - if s != nil { - out = append(out, fmt.Sprintf("'%v'", s)) - } - } - return strings.Join(out, " ") -} - -func cat(v ...interface{}) string { - v = removeNilElements(v) - r := strings.TrimSpace(strings.Repeat("%v ", len(v))) - return fmt.Sprintf(r, v...) -} - -func indent(spaces int, v string) string { - pad := strings.Repeat(" ", spaces) - return pad + strings.Replace(v, "\n", "\n"+pad, -1) -} - -func nindent(spaces int, v string) string { - return "\n" + indent(spaces, v) -} - -func replace(old, new, src string) string { - return strings.Replace(src, old, new, -1) -} - -func plural(one, many string, count int) string { - if count == 1 { - return one - } - return many -} - -func strslice(v interface{}) []string { - switch v := v.(type) { - case []string: - return v - case []interface{}: - b := make([]string, 0, len(v)) - for _, s := range v { - if s != nil { - b = append(b, strval(s)) - } - } - return b - default: - val := reflect.ValueOf(v) - switch val.Kind() { - case reflect.Array, reflect.Slice: - l := val.Len() - b := make([]string, 0, l) - for i := 0; i < l; i++ { - value := val.Index(i).Interface() - if value != nil { - b = append(b, strval(value)) - } - } - return b - default: - if v == nil { - return []string{} - } - - return []string{strval(v)} - } - } -} - -func removeNilElements(v []interface{}) []interface{} { - newSlice := make([]interface{}, 0, len(v)) - for _, i := range v { - if i != nil { - newSlice = append(newSlice, i) - } - } - return newSlice -} - -func strval(v interface{}) string { - switch v := v.(type) { - case string: - return v - case []byte: - return string(v) - case error: - return v.Error() - case fmt.Stringer: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func trunc(c int, s string) string { - if c < 0 && len(s)+c > 0 { - return s[len(s)+c:] - } - if c >= 0 && len(s) > c { - return s[:c] - } - return s -} - -func join(sep string, v interface{}) string { - return strings.Join(strslice(v), sep) -} - -func split(sep, orig string) map[string]string { - parts := strings.Split(orig, sep) - res := make(map[string]string, len(parts)) - for i, v := range parts { - res["_"+strconv.Itoa(i)] = v - } - return res -} - -func splitn(sep string, n int, orig string) map[string]string { - parts := strings.SplitN(orig, sep, n) - res := make(map[string]string, len(parts)) - for i, v := range parts { - res["_"+strconv.Itoa(i)] = v - } - return res -} - -// substring creates a substring of the given string. -// -// If start is < 0, this calls string[:end]. -// -// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:] -// -// Otherwise, this calls string[start, end]. -func substring(start, end int, s string) string { - if start < 0 { - return s[:end] - } - if end < 0 || end > len(s) { - return s[start:] - } - return s[start:end] -} diff --git a/vendor/github.com/go-task/slim-sprig/url.go b/vendor/github.com/go-task/slim-sprig/url.go deleted file mode 100644 index b8e120e19b..0000000000 --- a/vendor/github.com/go-task/slim-sprig/url.go +++ /dev/null @@ -1,66 +0,0 @@ -package sprig - -import ( - "fmt" - "net/url" - "reflect" -) - -func dictGetOrEmpty(dict map[string]interface{}, key string) string { - value, ok := dict[key] - if !ok { - return "" - } - tp := reflect.TypeOf(value).Kind() - if tp != reflect.String { - panic(fmt.Sprintf("unable to parse %s key, must be of type string, but %s found", key, tp.String())) - } - return reflect.ValueOf(value).String() -} - -// parses given URL to return dict object -func urlParse(v string) map[string]interface{} { - dict := map[string]interface{}{} - parsedURL, err := url.Parse(v) - if err != nil { - panic(fmt.Sprintf("unable to parse url: %s", err)) - } - dict["scheme"] = parsedURL.Scheme - dict["host"] = parsedURL.Host - dict["hostname"] = parsedURL.Hostname() - dict["path"] = parsedURL.Path - dict["query"] = parsedURL.RawQuery - dict["opaque"] = parsedURL.Opaque - dict["fragment"] = parsedURL.Fragment - if parsedURL.User != nil { - dict["userinfo"] = parsedURL.User.String() - } else { - dict["userinfo"] = "" - } - - return dict -} - -// join given dict to URL string -func urlJoin(d map[string]interface{}) string { - resURL := url.URL{ - Scheme: dictGetOrEmpty(d, "scheme"), - Host: dictGetOrEmpty(d, "host"), - Path: dictGetOrEmpty(d, "path"), - RawQuery: dictGetOrEmpty(d, "query"), - Opaque: dictGetOrEmpty(d, "opaque"), - Fragment: dictGetOrEmpty(d, "fragment"), - } - userinfo := dictGetOrEmpty(d, "userinfo") - var user *url.Userinfo - if userinfo != "" { - tempURL, err := url.Parse(fmt.Sprintf("proto://%s@host", userinfo)) - if err != nil { - panic(fmt.Sprintf("unable to parse userinfo in dict: %s", err)) - } - user = tempURL.User - } - - resURL.User = user - return resURL.String() -} diff --git a/vendor/github.com/google/pprof/AUTHORS b/vendor/github.com/google/pprof/AUTHORS deleted file mode 100644 index fd736cb1cf..0000000000 --- a/vendor/github.com/google/pprof/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -# This is the official list of pprof authors for copyright purposes. -# This file is distinct from the CONTRIBUTORS files. -# See the latter for an explanation. -# Names should be added to this file as: -# Name or Organization -# The email address is not required for organizations. -Google Inc. \ No newline at end of file diff --git a/vendor/github.com/google/pprof/CONTRIBUTORS b/vendor/github.com/google/pprof/CONTRIBUTORS deleted file mode 100644 index 8c8c37d2c8..0000000000 --- a/vendor/github.com/google/pprof/CONTRIBUTORS +++ /dev/null @@ -1,16 +0,0 @@ -# People who have agreed to one of the CLAs and can contribute patches. -# The AUTHORS file lists the copyright holders; this file -# lists people. For example, Google employees are listed here -# but not in AUTHORS, because Google holds the copyright. -# -# https://developers.google.com/open-source/cla/individual -# https://developers.google.com/open-source/cla/corporate -# -# Names should be added to this file as: -# Name -Raul Silvera -Tipp Moseley -Hyoun Kyu Cho -Martin Spier -Taco de Wolff -Andrew Hunter diff --git a/vendor/github.com/google/pprof/LICENSE b/vendor/github.com/google/pprof/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/vendor/github.com/google/pprof/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/google/pprof/profile/encode.go b/vendor/github.com/google/pprof/profile/encode.go deleted file mode 100644 index ab7f03ae26..0000000000 --- a/vendor/github.com/google/pprof/profile/encode.go +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 profile - -import ( - "errors" - "sort" -) - -func (p *Profile) decoder() []decoder { - return profileDecoder -} - -// preEncode populates the unexported fields to be used by encode -// (with suffix X) from the corresponding exported fields. The -// exported fields are cleared up to facilitate testing. -func (p *Profile) preEncode() { - strings := make(map[string]int) - addString(strings, "") - - for _, st := range p.SampleType { - st.typeX = addString(strings, st.Type) - st.unitX = addString(strings, st.Unit) - } - - for _, s := range p.Sample { - s.labelX = nil - var keys []string - for k := range s.Label { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - vs := s.Label[k] - for _, v := range vs { - s.labelX = append(s.labelX, - label{ - keyX: addString(strings, k), - strX: addString(strings, v), - }, - ) - } - } - var numKeys []string - for k := range s.NumLabel { - numKeys = append(numKeys, k) - } - sort.Strings(numKeys) - for _, k := range numKeys { - keyX := addString(strings, k) - vs := s.NumLabel[k] - units := s.NumUnit[k] - for i, v := range vs { - var unitX int64 - if len(units) != 0 { - unitX = addString(strings, units[i]) - } - s.labelX = append(s.labelX, - label{ - keyX: keyX, - numX: v, - unitX: unitX, - }, - ) - } - } - s.locationIDX = make([]uint64, len(s.Location)) - for i, loc := range s.Location { - s.locationIDX[i] = loc.ID - } - } - - for _, m := range p.Mapping { - m.fileX = addString(strings, m.File) - m.buildIDX = addString(strings, m.BuildID) - } - - for _, l := range p.Location { - for i, ln := range l.Line { - if ln.Function != nil { - l.Line[i].functionIDX = ln.Function.ID - } else { - l.Line[i].functionIDX = 0 - } - } - if l.Mapping != nil { - l.mappingIDX = l.Mapping.ID - } else { - l.mappingIDX = 0 - } - } - for _, f := range p.Function { - f.nameX = addString(strings, f.Name) - f.systemNameX = addString(strings, f.SystemName) - f.filenameX = addString(strings, f.Filename) - } - - p.dropFramesX = addString(strings, p.DropFrames) - p.keepFramesX = addString(strings, p.KeepFrames) - - if pt := p.PeriodType; pt != nil { - pt.typeX = addString(strings, pt.Type) - pt.unitX = addString(strings, pt.Unit) - } - - p.commentX = nil - for _, c := range p.Comments { - p.commentX = append(p.commentX, addString(strings, c)) - } - - p.defaultSampleTypeX = addString(strings, p.DefaultSampleType) - - p.stringTable = make([]string, len(strings)) - for s, i := range strings { - p.stringTable[i] = s - } -} - -func (p *Profile) encode(b *buffer) { - for _, x := range p.SampleType { - encodeMessage(b, 1, x) - } - for _, x := range p.Sample { - encodeMessage(b, 2, x) - } - for _, x := range p.Mapping { - encodeMessage(b, 3, x) - } - for _, x := range p.Location { - encodeMessage(b, 4, x) - } - for _, x := range p.Function { - encodeMessage(b, 5, x) - } - encodeStrings(b, 6, p.stringTable) - encodeInt64Opt(b, 7, p.dropFramesX) - encodeInt64Opt(b, 8, p.keepFramesX) - encodeInt64Opt(b, 9, p.TimeNanos) - encodeInt64Opt(b, 10, p.DurationNanos) - if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) { - encodeMessage(b, 11, p.PeriodType) - } - encodeInt64Opt(b, 12, p.Period) - encodeInt64s(b, 13, p.commentX) - encodeInt64(b, 14, p.defaultSampleTypeX) -} - -var profileDecoder = []decoder{ - nil, // 0 - // repeated ValueType sample_type = 1 - func(b *buffer, m message) error { - x := new(ValueType) - pp := m.(*Profile) - pp.SampleType = append(pp.SampleType, x) - return decodeMessage(b, x) - }, - // repeated Sample sample = 2 - func(b *buffer, m message) error { - x := new(Sample) - pp := m.(*Profile) - pp.Sample = append(pp.Sample, x) - return decodeMessage(b, x) - }, - // repeated Mapping mapping = 3 - func(b *buffer, m message) error { - x := new(Mapping) - pp := m.(*Profile) - pp.Mapping = append(pp.Mapping, x) - return decodeMessage(b, x) - }, - // repeated Location location = 4 - func(b *buffer, m message) error { - x := new(Location) - x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer - pp := m.(*Profile) - pp.Location = append(pp.Location, x) - err := decodeMessage(b, x) - var tmp []Line - x.Line = append(tmp, x.Line...) // Shrink to allocated size - return err - }, - // repeated Function function = 5 - func(b *buffer, m message) error { - x := new(Function) - pp := m.(*Profile) - pp.Function = append(pp.Function, x) - return decodeMessage(b, x) - }, - // repeated string string_table = 6 - func(b *buffer, m message) error { - err := decodeStrings(b, &m.(*Profile).stringTable) - if err != nil { - return err - } - if m.(*Profile).stringTable[0] != "" { - return errors.New("string_table[0] must be ''") - } - return nil - }, - // int64 drop_frames = 7 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) }, - // int64 keep_frames = 8 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) }, - // int64 time_nanos = 9 - func(b *buffer, m message) error { - if m.(*Profile).TimeNanos != 0 { - return errConcatProfile - } - return decodeInt64(b, &m.(*Profile).TimeNanos) - }, - // int64 duration_nanos = 10 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) }, - // ValueType period_type = 11 - func(b *buffer, m message) error { - x := new(ValueType) - pp := m.(*Profile) - pp.PeriodType = x - return decodeMessage(b, x) - }, - // int64 period = 12 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) }, - // repeated int64 comment = 13 - func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) }, - // int64 defaultSampleType = 14 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) }, -} - -// postDecode takes the unexported fields populated by decode (with -// suffix X) and populates the corresponding exported fields. -// The unexported fields are cleared up to facilitate testing. -func (p *Profile) postDecode() error { - var err error - mappings := make(map[uint64]*Mapping, len(p.Mapping)) - mappingIds := make([]*Mapping, len(p.Mapping)+1) - for _, m := range p.Mapping { - m.File, err = getString(p.stringTable, &m.fileX, err) - m.BuildID, err = getString(p.stringTable, &m.buildIDX, err) - if m.ID < uint64(len(mappingIds)) { - mappingIds[m.ID] = m - } else { - mappings[m.ID] = m - } - } - - functions := make(map[uint64]*Function, len(p.Function)) - functionIds := make([]*Function, len(p.Function)+1) - for _, f := range p.Function { - f.Name, err = getString(p.stringTable, &f.nameX, err) - f.SystemName, err = getString(p.stringTable, &f.systemNameX, err) - f.Filename, err = getString(p.stringTable, &f.filenameX, err) - if f.ID < uint64(len(functionIds)) { - functionIds[f.ID] = f - } else { - functions[f.ID] = f - } - } - - locations := make(map[uint64]*Location, len(p.Location)) - locationIds := make([]*Location, len(p.Location)+1) - for _, l := range p.Location { - if id := l.mappingIDX; id < uint64(len(mappingIds)) { - l.Mapping = mappingIds[id] - } else { - l.Mapping = mappings[id] - } - l.mappingIDX = 0 - for i, ln := range l.Line { - if id := ln.functionIDX; id != 0 { - l.Line[i].functionIDX = 0 - if id < uint64(len(functionIds)) { - l.Line[i].Function = functionIds[id] - } else { - l.Line[i].Function = functions[id] - } - } - } - if l.ID < uint64(len(locationIds)) { - locationIds[l.ID] = l - } else { - locations[l.ID] = l - } - } - - for _, st := range p.SampleType { - st.Type, err = getString(p.stringTable, &st.typeX, err) - st.Unit, err = getString(p.stringTable, &st.unitX, err) - } - - for _, s := range p.Sample { - labels := make(map[string][]string, len(s.labelX)) - numLabels := make(map[string][]int64, len(s.labelX)) - numUnits := make(map[string][]string, len(s.labelX)) - for _, l := range s.labelX { - var key, value string - key, err = getString(p.stringTable, &l.keyX, err) - if l.strX != 0 { - value, err = getString(p.stringTable, &l.strX, err) - labels[key] = append(labels[key], value) - } else if l.numX != 0 || l.unitX != 0 { - numValues := numLabels[key] - units := numUnits[key] - if l.unitX != 0 { - var unit string - unit, err = getString(p.stringTable, &l.unitX, err) - units = padStringArray(units, len(numValues)) - numUnits[key] = append(units, unit) - } - numLabels[key] = append(numLabels[key], l.numX) - } - } - if len(labels) > 0 { - s.Label = labels - } - if len(numLabels) > 0 { - s.NumLabel = numLabels - for key, units := range numUnits { - if len(units) > 0 { - numUnits[key] = padStringArray(units, len(numLabels[key])) - } - } - s.NumUnit = numUnits - } - s.Location = make([]*Location, len(s.locationIDX)) - for i, lid := range s.locationIDX { - if lid < uint64(len(locationIds)) { - s.Location[i] = locationIds[lid] - } else { - s.Location[i] = locations[lid] - } - } - s.locationIDX = nil - } - - p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err) - p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err) - - if pt := p.PeriodType; pt == nil { - p.PeriodType = &ValueType{} - } - - if pt := p.PeriodType; pt != nil { - pt.Type, err = getString(p.stringTable, &pt.typeX, err) - pt.Unit, err = getString(p.stringTable, &pt.unitX, err) - } - - for _, i := range p.commentX { - var c string - c, err = getString(p.stringTable, &i, err) - p.Comments = append(p.Comments, c) - } - - p.commentX = nil - p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err) - p.stringTable = nil - return err -} - -// padStringArray pads arr with enough empty strings to make arr -// length l when arr's length is less than l. -func padStringArray(arr []string, l int) []string { - if l <= len(arr) { - return arr - } - return append(arr, make([]string, l-len(arr))...) -} - -func (p *ValueType) decoder() []decoder { - return valueTypeDecoder -} - -func (p *ValueType) encode(b *buffer) { - encodeInt64Opt(b, 1, p.typeX) - encodeInt64Opt(b, 2, p.unitX) -} - -var valueTypeDecoder = []decoder{ - nil, // 0 - // optional int64 type = 1 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) }, - // optional int64 unit = 2 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) }, -} - -func (p *Sample) decoder() []decoder { - return sampleDecoder -} - -func (p *Sample) encode(b *buffer) { - encodeUint64s(b, 1, p.locationIDX) - encodeInt64s(b, 2, p.Value) - for _, x := range p.labelX { - encodeMessage(b, 3, x) - } -} - -var sampleDecoder = []decoder{ - nil, // 0 - // repeated uint64 location = 1 - func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) }, - // repeated int64 value = 2 - func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) }, - // repeated Label label = 3 - func(b *buffer, m message) error { - s := m.(*Sample) - n := len(s.labelX) - s.labelX = append(s.labelX, label{}) - return decodeMessage(b, &s.labelX[n]) - }, -} - -func (p label) decoder() []decoder { - return labelDecoder -} - -func (p label) encode(b *buffer) { - encodeInt64Opt(b, 1, p.keyX) - encodeInt64Opt(b, 2, p.strX) - encodeInt64Opt(b, 3, p.numX) - encodeInt64Opt(b, 4, p.unitX) -} - -var labelDecoder = []decoder{ - nil, // 0 - // optional int64 key = 1 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) }, - // optional int64 str = 2 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) }, - // optional int64 num = 3 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) }, - // optional int64 num = 4 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) }, -} - -func (p *Mapping) decoder() []decoder { - return mappingDecoder -} - -func (p *Mapping) encode(b *buffer) { - encodeUint64Opt(b, 1, p.ID) - encodeUint64Opt(b, 2, p.Start) - encodeUint64Opt(b, 3, p.Limit) - encodeUint64Opt(b, 4, p.Offset) - encodeInt64Opt(b, 5, p.fileX) - encodeInt64Opt(b, 6, p.buildIDX) - encodeBoolOpt(b, 7, p.HasFunctions) - encodeBoolOpt(b, 8, p.HasFilenames) - encodeBoolOpt(b, 9, p.HasLineNumbers) - encodeBoolOpt(b, 10, p.HasInlineFrames) -} - -var mappingDecoder = []decoder{ - nil, // 0 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) }, // optional uint64 id = 1 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) }, // optional uint64 memory_offset = 2 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) }, // optional uint64 memory_limit = 3 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) }, // optional uint64 file_offset = 4 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) }, // optional int64 filename = 5 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) }, // optional int64 build_id = 6 - func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) }, // optional bool has_functions = 7 - func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) }, // optional bool has_filenames = 8 - func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) }, // optional bool has_line_numbers = 9 - func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10 -} - -func (p *Location) decoder() []decoder { - return locationDecoder -} - -func (p *Location) encode(b *buffer) { - encodeUint64Opt(b, 1, p.ID) - encodeUint64Opt(b, 2, p.mappingIDX) - encodeUint64Opt(b, 3, p.Address) - for i := range p.Line { - encodeMessage(b, 4, &p.Line[i]) - } - encodeBoolOpt(b, 5, p.IsFolded) -} - -var locationDecoder = []decoder{ - nil, // 0 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) }, // optional uint64 id = 1; - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2; - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) }, // optional uint64 address = 3; - func(b *buffer, m message) error { // repeated Line line = 4 - pp := m.(*Location) - n := len(pp.Line) - pp.Line = append(pp.Line, Line{}) - return decodeMessage(b, &pp.Line[n]) - }, - func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5; -} - -func (p *Line) decoder() []decoder { - return lineDecoder -} - -func (p *Line) encode(b *buffer) { - encodeUint64Opt(b, 1, p.functionIDX) - encodeInt64Opt(b, 2, p.Line) -} - -var lineDecoder = []decoder{ - nil, // 0 - // optional uint64 function_id = 1 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) }, - // optional int64 line = 2 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) }, -} - -func (p *Function) decoder() []decoder { - return functionDecoder -} - -func (p *Function) encode(b *buffer) { - encodeUint64Opt(b, 1, p.ID) - encodeInt64Opt(b, 2, p.nameX) - encodeInt64Opt(b, 3, p.systemNameX) - encodeInt64Opt(b, 4, p.filenameX) - encodeInt64Opt(b, 5, p.StartLine) -} - -var functionDecoder = []decoder{ - nil, // 0 - // optional uint64 id = 1 - func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) }, - // optional int64 function_name = 2 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) }, - // optional int64 function_system_name = 3 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) }, - // repeated int64 filename = 4 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) }, - // optional int64 start_line = 5 - func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) }, -} - -func addString(strings map[string]int, s string) int64 { - i, ok := strings[s] - if !ok { - i = len(strings) - strings[s] = i - } - return int64(i) -} - -func getString(strings []string, strng *int64, err error) (string, error) { - if err != nil { - return "", err - } - s := int(*strng) - if s < 0 || s >= len(strings) { - return "", errMalformed - } - *strng = 0 - return strings[s], nil -} diff --git a/vendor/github.com/google/pprof/profile/filter.go b/vendor/github.com/google/pprof/profile/filter.go deleted file mode 100644 index ea8e66c68d..0000000000 --- a/vendor/github.com/google/pprof/profile/filter.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 profile - -// Implements methods to filter samples from profiles. - -import "regexp" - -// FilterSamplesByName filters the samples in a profile and only keeps -// samples where at least one frame matches focus but none match ignore. -// Returns true is the corresponding regexp matched at least one sample. -func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) { - focusOrIgnore := make(map[uint64]bool) - hidden := make(map[uint64]bool) - for _, l := range p.Location { - if ignore != nil && l.matchesName(ignore) { - im = true - focusOrIgnore[l.ID] = false - } else if focus == nil || l.matchesName(focus) { - fm = true - focusOrIgnore[l.ID] = true - } - - if hide != nil && l.matchesName(hide) { - hm = true - l.Line = l.unmatchedLines(hide) - if len(l.Line) == 0 { - hidden[l.ID] = true - } - } - if show != nil { - l.Line = l.matchedLines(show) - if len(l.Line) == 0 { - hidden[l.ID] = true - } else { - hnm = true - } - } - } - - s := make([]*Sample, 0, len(p.Sample)) - for _, sample := range p.Sample { - if focusedAndNotIgnored(sample.Location, focusOrIgnore) { - if len(hidden) > 0 { - var locs []*Location - for _, loc := range sample.Location { - if !hidden[loc.ID] { - locs = append(locs, loc) - } - } - if len(locs) == 0 { - // Remove sample with no locations (by not adding it to s). - continue - } - sample.Location = locs - } - s = append(s, sample) - } - } - p.Sample = s - - return -} - -// ShowFrom drops all stack frames above the highest matching frame and returns -// whether a match was found. If showFrom is nil it returns false and does not -// modify the profile. -// -// Example: consider a sample with frames [A, B, C, B], where A is the root. -// ShowFrom(nil) returns false and has frames [A, B, C, B]. -// ShowFrom(A) returns true and has frames [A, B, C, B]. -// ShowFrom(B) returns true and has frames [B, C, B]. -// ShowFrom(C) returns true and has frames [C, B]. -// ShowFrom(D) returns false and drops the sample because no frames remain. -func (p *Profile) ShowFrom(showFrom *regexp.Regexp) (matched bool) { - if showFrom == nil { - return false - } - // showFromLocs stores location IDs that matched ShowFrom. - showFromLocs := make(map[uint64]bool) - // Apply to locations. - for _, loc := range p.Location { - if filterShowFromLocation(loc, showFrom) { - showFromLocs[loc.ID] = true - matched = true - } - } - // For all samples, strip locations after the highest matching one. - s := make([]*Sample, 0, len(p.Sample)) - for _, sample := range p.Sample { - for i := len(sample.Location) - 1; i >= 0; i-- { - if showFromLocs[sample.Location[i].ID] { - sample.Location = sample.Location[:i+1] - s = append(s, sample) - break - } - } - } - p.Sample = s - return matched -} - -// filterShowFromLocation tests a showFrom regex against a location, removes -// lines after the last match and returns whether a match was found. If the -// mapping is matched, then all lines are kept. -func filterShowFromLocation(loc *Location, showFrom *regexp.Regexp) bool { - if m := loc.Mapping; m != nil && showFrom.MatchString(m.File) { - return true - } - if i := loc.lastMatchedLineIndex(showFrom); i >= 0 { - loc.Line = loc.Line[:i+1] - return true - } - return false -} - -// lastMatchedLineIndex returns the index of the last line that matches a regex, -// or -1 if no match is found. -func (loc *Location) lastMatchedLineIndex(re *regexp.Regexp) int { - for i := len(loc.Line) - 1; i >= 0; i-- { - if fn := loc.Line[i].Function; fn != nil { - if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { - return i - } - } - } - return -1 -} - -// FilterTagsByName filters the tags in a profile and only keeps -// tags that match show and not hide. -func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) { - matchRemove := func(name string) bool { - matchShow := show == nil || show.MatchString(name) - matchHide := hide != nil && hide.MatchString(name) - - if matchShow { - sm = true - } - if matchHide { - hm = true - } - return !matchShow || matchHide - } - for _, s := range p.Sample { - for lab := range s.Label { - if matchRemove(lab) { - delete(s.Label, lab) - } - } - for lab := range s.NumLabel { - if matchRemove(lab) { - delete(s.NumLabel, lab) - } - } - } - return -} - -// matchesName returns whether the location matches the regular -// expression. It checks any available function names, file names, and -// mapping object filename. -func (loc *Location) matchesName(re *regexp.Regexp) bool { - for _, ln := range loc.Line { - if fn := ln.Function; fn != nil { - if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { - return true - } - } - } - if m := loc.Mapping; m != nil && re.MatchString(m.File) { - return true - } - return false -} - -// unmatchedLines returns the lines in the location that do not match -// the regular expression. -func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line { - if m := loc.Mapping; m != nil && re.MatchString(m.File) { - return nil - } - var lines []Line - for _, ln := range loc.Line { - if fn := ln.Function; fn != nil { - if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { - continue - } - } - lines = append(lines, ln) - } - return lines -} - -// matchedLines returns the lines in the location that match -// the regular expression. -func (loc *Location) matchedLines(re *regexp.Regexp) []Line { - if m := loc.Mapping; m != nil && re.MatchString(m.File) { - return loc.Line - } - var lines []Line - for _, ln := range loc.Line { - if fn := ln.Function; fn != nil { - if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) { - continue - } - } - lines = append(lines, ln) - } - return lines -} - -// focusedAndNotIgnored looks up a slice of ids against a map of -// focused/ignored locations. The map only contains locations that are -// explicitly focused or ignored. Returns whether there is at least -// one focused location but no ignored locations. -func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool { - var f bool - for _, loc := range locs { - if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore { - if focus { - // Found focused location. Must keep searching in case there - // is an ignored one as well. - f = true - } else { - // Found ignored location. Can return false right away. - return false - } - } - } - return f -} - -// TagMatch selects tags for filtering -type TagMatch func(s *Sample) bool - -// FilterSamplesByTag removes all samples from the profile, except -// those that match focus and do not match the ignore regular -// expression. -func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) { - samples := make([]*Sample, 0, len(p.Sample)) - for _, s := range p.Sample { - focused, ignored := true, false - if focus != nil { - focused = focus(s) - } - if ignore != nil { - ignored = ignore(s) - } - fm = fm || focused - im = im || ignored - if focused && !ignored { - samples = append(samples, s) - } - } - p.Sample = samples - return -} diff --git a/vendor/github.com/google/pprof/profile/index.go b/vendor/github.com/google/pprof/profile/index.go deleted file mode 100644 index bef1d60467..0000000000 --- a/vendor/github.com/google/pprof/profile/index.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 profile - -import ( - "fmt" - "strconv" - "strings" -) - -// SampleIndexByName returns the appropriate index for a value of sample index. -// If numeric, it returns the number, otherwise it looks up the text in the -// profile sample types. -func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) { - if sampleIndex == "" { - if dst := p.DefaultSampleType; dst != "" { - for i, t := range sampleTypes(p) { - if t == dst { - return i, nil - } - } - } - // By default select the last sample value - return len(p.SampleType) - 1, nil - } - if i, err := strconv.Atoi(sampleIndex); err == nil { - if i < 0 || i >= len(p.SampleType) { - return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1) - } - return i, nil - } - - // Remove the inuse_ prefix to support legacy pprof options - // "inuse_space" and "inuse_objects" for profiles containing types - // "space" and "objects". - noInuse := strings.TrimPrefix(sampleIndex, "inuse_") - for i, t := range p.SampleType { - if t.Type == sampleIndex || t.Type == noInuse { - return i, nil - } - } - - return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p)) -} - -func sampleTypes(p *Profile) []string { - types := make([]string, len(p.SampleType)) - for i, t := range p.SampleType { - types[i] = t.Type - } - return types -} diff --git a/vendor/github.com/google/pprof/profile/legacy_java_profile.go b/vendor/github.com/google/pprof/profile/legacy_java_profile.go deleted file mode 100644 index 91f45e53c6..0000000000 --- a/vendor/github.com/google/pprof/profile/legacy_java_profile.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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. - -// This file implements parsers to convert java legacy profiles into -// the profile.proto format. - -package profile - -import ( - "bytes" - "fmt" - "io" - "path/filepath" - "regexp" - "strconv" - "strings" -) - -var ( - attributeRx = regexp.MustCompile(`([\w ]+)=([\w ]+)`) - javaSampleRx = regexp.MustCompile(` *(\d+) +(\d+) +@ +([ x0-9a-f]*)`) - javaLocationRx = regexp.MustCompile(`^\s*0x([[:xdigit:]]+)\s+(.*)\s*$`) - javaLocationFileLineRx = regexp.MustCompile(`^(.*)\s+\((.+):(-?[[:digit:]]+)\)$`) - javaLocationPathRx = regexp.MustCompile(`^(.*)\s+\((.*)\)$`) -) - -// javaCPUProfile returns a new Profile from profilez data. -// b is the profile bytes after the header, period is the profiling -// period, and parse is a function to parse 8-byte chunks from the -// profile in its native endianness. -func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) { - p := &Profile{ - Period: period * 1000, - PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"}, - SampleType: []*ValueType{{Type: "samples", Unit: "count"}, {Type: "cpu", Unit: "nanoseconds"}}, - } - var err error - var locs map[uint64]*Location - if b, locs, err = parseCPUSamples(b, parse, false, p); err != nil { - return nil, err - } - - if err = parseJavaLocations(b, locs, p); err != nil { - return nil, err - } - - // Strip out addresses for better merge. - if err = p.Aggregate(true, true, true, true, false); err != nil { - return nil, err - } - - return p, nil -} - -// parseJavaProfile returns a new profile from heapz or contentionz -// data. b is the profile bytes after the header. -func parseJavaProfile(b []byte) (*Profile, error) { - h := bytes.SplitAfterN(b, []byte("\n"), 2) - if len(h) < 2 { - return nil, errUnrecognized - } - - p := &Profile{ - PeriodType: &ValueType{}, - } - header := string(bytes.TrimSpace(h[0])) - - var err error - var pType string - switch header { - case "--- heapz 1 ---": - pType = "heap" - case "--- contentionz 1 ---": - pType = "contention" - default: - return nil, errUnrecognized - } - - if b, err = parseJavaHeader(pType, h[1], p); err != nil { - return nil, err - } - var locs map[uint64]*Location - if b, locs, err = parseJavaSamples(pType, b, p); err != nil { - return nil, err - } - if err = parseJavaLocations(b, locs, p); err != nil { - return nil, err - } - - // Strip out addresses for better merge. - if err = p.Aggregate(true, true, true, true, false); err != nil { - return nil, err - } - - return p, nil -} - -// parseJavaHeader parses the attribute section on a java profile and -// populates a profile. Returns the remainder of the buffer after all -// attributes. -func parseJavaHeader(pType string, b []byte, p *Profile) ([]byte, error) { - nextNewLine := bytes.IndexByte(b, byte('\n')) - for nextNewLine != -1 { - line := string(bytes.TrimSpace(b[0:nextNewLine])) - if line != "" { - h := attributeRx.FindStringSubmatch(line) - if h == nil { - // Not a valid attribute, exit. - return b, nil - } - - attribute, value := strings.TrimSpace(h[1]), strings.TrimSpace(h[2]) - var err error - switch pType + "/" + attribute { - case "heap/format", "cpu/format", "contention/format": - if value != "java" { - return nil, errUnrecognized - } - case "heap/resolution": - p.SampleType = []*ValueType{ - {Type: "inuse_objects", Unit: "count"}, - {Type: "inuse_space", Unit: value}, - } - case "contention/resolution": - p.SampleType = []*ValueType{ - {Type: "contentions", Unit: "count"}, - {Type: "delay", Unit: value}, - } - case "contention/sampling period": - p.PeriodType = &ValueType{ - Type: "contentions", Unit: "count", - } - if p.Period, err = strconv.ParseInt(value, 0, 64); err != nil { - return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err) - } - case "contention/ms since reset": - millis, err := strconv.ParseInt(value, 0, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err) - } - p.DurationNanos = millis * 1000 * 1000 - default: - return nil, errUnrecognized - } - } - // Grab next line. - b = b[nextNewLine+1:] - nextNewLine = bytes.IndexByte(b, byte('\n')) - } - return b, nil -} - -// parseJavaSamples parses the samples from a java profile and -// populates the Samples in a profile. Returns the remainder of the -// buffer after the samples. -func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*Location, error) { - nextNewLine := bytes.IndexByte(b, byte('\n')) - locs := make(map[uint64]*Location) - for nextNewLine != -1 { - line := string(bytes.TrimSpace(b[0:nextNewLine])) - if line != "" { - sample := javaSampleRx.FindStringSubmatch(line) - if sample == nil { - // Not a valid sample, exit. - return b, locs, nil - } - - // Java profiles have data/fields inverted compared to other - // profile types. - var err error - value1, value2, value3 := sample[2], sample[1], sample[3] - addrs, err := parseHexAddresses(value3) - if err != nil { - return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - - var sloc []*Location - for _, addr := range addrs { - loc := locs[addr] - if locs[addr] == nil { - loc = &Location{ - Address: addr, - } - p.Location = append(p.Location, loc) - locs[addr] = loc - } - sloc = append(sloc, loc) - } - s := &Sample{ - Value: make([]int64, 2), - Location: sloc, - } - - if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil { - return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err) - } - if s.Value[1], err = strconv.ParseInt(value2, 0, 64); err != nil { - return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err) - } - - switch pType { - case "heap": - const javaHeapzSamplingRate = 524288 // 512K - if s.Value[0] == 0 { - return nil, nil, fmt.Errorf("parsing sample %s: second value must be non-zero", line) - } - s.NumLabel = map[string][]int64{"bytes": {s.Value[1] / s.Value[0]}} - s.Value[0], s.Value[1] = scaleHeapSample(s.Value[0], s.Value[1], javaHeapzSamplingRate) - case "contention": - if period := p.Period; period != 0 { - s.Value[0] = s.Value[0] * p.Period - s.Value[1] = s.Value[1] * p.Period - } - } - p.Sample = append(p.Sample, s) - } - // Grab next line. - b = b[nextNewLine+1:] - nextNewLine = bytes.IndexByte(b, byte('\n')) - } - return b, locs, nil -} - -// parseJavaLocations parses the location information in a java -// profile and populates the Locations in a profile. It uses the -// location addresses from the profile as both the ID of each -// location. -func parseJavaLocations(b []byte, locs map[uint64]*Location, p *Profile) error { - r := bytes.NewBuffer(b) - fns := make(map[string]*Function) - for { - line, err := r.ReadString('\n') - if err != nil { - if err != io.EOF { - return err - } - if line == "" { - break - } - } - - if line = strings.TrimSpace(line); line == "" { - continue - } - - jloc := javaLocationRx.FindStringSubmatch(line) - if len(jloc) != 3 { - continue - } - addr, err := strconv.ParseUint(jloc[1], 16, 64) - if err != nil { - return fmt.Errorf("parsing sample %s: %v", line, err) - } - loc := locs[addr] - if loc == nil { - // Unused/unseen - continue - } - var lineFunc, lineFile string - var lineNo int64 - - if fileLine := javaLocationFileLineRx.FindStringSubmatch(jloc[2]); len(fileLine) == 4 { - // Found a line of the form: "function (file:line)" - lineFunc, lineFile = fileLine[1], fileLine[2] - if n, err := strconv.ParseInt(fileLine[3], 10, 64); err == nil && n > 0 { - lineNo = n - } - } else if filePath := javaLocationPathRx.FindStringSubmatch(jloc[2]); len(filePath) == 3 { - // If there's not a file:line, it's a shared library path. - // The path isn't interesting, so just give the .so. - lineFunc, lineFile = filePath[1], filepath.Base(filePath[2]) - } else if strings.Contains(jloc[2], "generated stub/JIT") { - lineFunc = "STUB" - } else { - // Treat whole line as the function name. This is used by the - // java agent for internal states such as "GC" or "VM". - lineFunc = jloc[2] - } - fn := fns[lineFunc] - - if fn == nil { - fn = &Function{ - Name: lineFunc, - SystemName: lineFunc, - Filename: lineFile, - } - fns[lineFunc] = fn - p.Function = append(p.Function, fn) - } - loc.Line = []Line{ - { - Function: fn, - Line: lineNo, - }, - } - loc.Address = 0 - } - - p.remapLocationIDs() - p.remapFunctionIDs() - p.remapMappingIDs() - - return nil -} diff --git a/vendor/github.com/google/pprof/profile/legacy_profile.go b/vendor/github.com/google/pprof/profile/legacy_profile.go deleted file mode 100644 index 0c8f3bb5b7..0000000000 --- a/vendor/github.com/google/pprof/profile/legacy_profile.go +++ /dev/null @@ -1,1225 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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. - -// This file implements parsers to convert legacy profiles into the -// profile.proto format. - -package profile - -import ( - "bufio" - "bytes" - "fmt" - "io" - "math" - "regexp" - "strconv" - "strings" -) - -var ( - countStartRE = regexp.MustCompile(`\A(\S+) profile: total \d+\z`) - countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\z`) - - heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`) - heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`) - - contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`) - - hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`) - - growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz?`) - - fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz?`) - - threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`) - threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`) - - // Regular expressions to parse process mappings. Support the format used by Linux /proc/.../maps and other tools. - // Recommended format: - // Start End object file name offset(optional) linker build id - // 0x40000-0x80000 /path/to/binary (@FF00) abc123456 - spaceDigits = `\s+[[:digit:]]+` - hexPair = `\s+[[:xdigit:]]+:[[:xdigit:]]+` - oSpace = `\s*` - // Capturing expressions. - cHex = `(?:0x)?([[:xdigit:]]+)` - cHexRange = `\s*` + cHex + `[\s-]?` + oSpace + cHex + `:?` - cSpaceString = `(?:\s+(\S+))?` - cSpaceHex = `(?:\s+([[:xdigit:]]+))?` - cSpaceAtOffset = `(?:\s+\(@([[:xdigit:]]+)\))?` - cPerm = `(?:\s+([-rwxp]+))?` - - procMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceHex + hexPair + spaceDigits + cSpaceString) - briefMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceString + cSpaceAtOffset + cSpaceHex) - - // Regular expression to parse log data, of the form: - // ... file:line] msg... - logInfoRE = regexp.MustCompile(`^[^\[\]]+:[0-9]+]\s`) -) - -func isSpaceOrComment(line string) bool { - trimmed := strings.TrimSpace(line) - return len(trimmed) == 0 || trimmed[0] == '#' -} - -// parseGoCount parses a Go count profile (e.g., threadcreate or -// goroutine) and returns a new Profile. -func parseGoCount(b []byte) (*Profile, error) { - s := bufio.NewScanner(bytes.NewBuffer(b)) - // Skip comments at the beginning of the file. - for s.Scan() && isSpaceOrComment(s.Text()) { - } - if err := s.Err(); err != nil { - return nil, err - } - m := countStartRE.FindStringSubmatch(s.Text()) - if m == nil { - return nil, errUnrecognized - } - profileType := m[1] - p := &Profile{ - PeriodType: &ValueType{Type: profileType, Unit: "count"}, - Period: 1, - SampleType: []*ValueType{{Type: profileType, Unit: "count"}}, - } - locations := make(map[uint64]*Location) - for s.Scan() { - line := s.Text() - if isSpaceOrComment(line) { - continue - } - if strings.HasPrefix(line, "---") { - break - } - m := countRE.FindStringSubmatch(line) - if m == nil { - return nil, errMalformed - } - n, err := strconv.ParseInt(m[1], 0, 64) - if err != nil { - return nil, errMalformed - } - fields := strings.Fields(m[2]) - locs := make([]*Location, 0, len(fields)) - for _, stk := range fields { - addr, err := strconv.ParseUint(stk, 0, 64) - if err != nil { - return nil, errMalformed - } - // Adjust all frames by -1 to land on top of the call instruction. - addr-- - loc := locations[addr] - if loc == nil { - loc = &Location{ - Address: addr, - } - locations[addr] = loc - p.Location = append(p.Location, loc) - } - locs = append(locs, loc) - } - p.Sample = append(p.Sample, &Sample{ - Location: locs, - Value: []int64{n}, - }) - } - if err := s.Err(); err != nil { - return nil, err - } - - if err := parseAdditionalSections(s, p); err != nil { - return nil, err - } - return p, nil -} - -// remapLocationIDs ensures there is a location for each address -// referenced by a sample, and remaps the samples to point to the new -// location ids. -func (p *Profile) remapLocationIDs() { - seen := make(map[*Location]bool, len(p.Location)) - var locs []*Location - - for _, s := range p.Sample { - for _, l := range s.Location { - if seen[l] { - continue - } - l.ID = uint64(len(locs) + 1) - locs = append(locs, l) - seen[l] = true - } - } - p.Location = locs -} - -func (p *Profile) remapFunctionIDs() { - seen := make(map[*Function]bool, len(p.Function)) - var fns []*Function - - for _, l := range p.Location { - for _, ln := range l.Line { - fn := ln.Function - if fn == nil || seen[fn] { - continue - } - fn.ID = uint64(len(fns) + 1) - fns = append(fns, fn) - seen[fn] = true - } - } - p.Function = fns -} - -// remapMappingIDs matches location addresses with existing mappings -// and updates them appropriately. This is O(N*M), if this ever shows -// up as a bottleneck, evaluate sorting the mappings and doing a -// binary search, which would make it O(N*log(M)). -func (p *Profile) remapMappingIDs() { - // Some profile handlers will incorrectly set regions for the main - // executable if its section is remapped. Fix them through heuristics. - - if len(p.Mapping) > 0 { - // Remove the initial mapping if named '/anon_hugepage' and has a - // consecutive adjacent mapping. - if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") { - if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start { - p.Mapping = p.Mapping[1:] - } - } - } - - // Subtract the offset from the start of the main mapping if it - // ends up at a recognizable start address. - if len(p.Mapping) > 0 { - const expectedStart = 0x400000 - if m := p.Mapping[0]; m.Start-m.Offset == expectedStart { - m.Start = expectedStart - m.Offset = 0 - } - } - - // Associate each location with an address to the corresponding - // mapping. Create fake mapping if a suitable one isn't found. - var fake *Mapping -nextLocation: - for _, l := range p.Location { - a := l.Address - if l.Mapping != nil || a == 0 { - continue - } - for _, m := range p.Mapping { - if m.Start <= a && a < m.Limit { - l.Mapping = m - continue nextLocation - } - } - // Work around legacy handlers failing to encode the first - // part of mappings split into adjacent ranges. - for _, m := range p.Mapping { - if m.Offset != 0 && m.Start-m.Offset <= a && a < m.Start { - m.Start -= m.Offset - m.Offset = 0 - l.Mapping = m - continue nextLocation - } - } - // If there is still no mapping, create a fake one. - // This is important for the Go legacy handler, which produced - // no mappings. - if fake == nil { - fake = &Mapping{ - ID: 1, - Limit: ^uint64(0), - } - p.Mapping = append(p.Mapping, fake) - } - l.Mapping = fake - } - - // Reset all mapping IDs. - for i, m := range p.Mapping { - m.ID = uint64(i + 1) - } -} - -var cpuInts = []func([]byte) (uint64, []byte){ - get32l, - get32b, - get64l, - get64b, -} - -func get32l(b []byte) (uint64, []byte) { - if len(b) < 4 { - return 0, nil - } - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:] -} - -func get32b(b []byte) (uint64, []byte) { - if len(b) < 4 { - return 0, nil - } - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:] -} - -func get64l(b []byte) (uint64, []byte) { - if len(b) < 8 { - return 0, nil - } - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:] -} - -func get64b(b []byte) (uint64, []byte) { - if len(b) < 8 { - return 0, nil - } - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:] -} - -// parseCPU parses a profilez legacy profile and returns a newly -// populated Profile. -// -// The general format for profilez samples is a sequence of words in -// binary format. The first words are a header with the following data: -// 1st word -- 0 -// 2nd word -- 3 -// 3rd word -- 0 if a c++ application, 1 if a java application. -// 4th word -- Sampling period (in microseconds). -// 5th word -- Padding. -func parseCPU(b []byte) (*Profile, error) { - var parse func([]byte) (uint64, []byte) - var n1, n2, n3, n4, n5 uint64 - for _, parse = range cpuInts { - var tmp []byte - n1, tmp = parse(b) - n2, tmp = parse(tmp) - n3, tmp = parse(tmp) - n4, tmp = parse(tmp) - n5, tmp = parse(tmp) - - if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 { - b = tmp - return cpuProfile(b, int64(n4), parse) - } - if tmp != nil && n1 == 0 && n2 == 3 && n3 == 1 && n4 > 0 && n5 == 0 { - b = tmp - return javaCPUProfile(b, int64(n4), parse) - } - } - return nil, errUnrecognized -} - -// cpuProfile returns a new Profile from C++ profilez data. -// b is the profile bytes after the header, period is the profiling -// period, and parse is a function to parse 8-byte chunks from the -// profile in its native endianness. -func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) { - p := &Profile{ - Period: period * 1000, - PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"}, - SampleType: []*ValueType{ - {Type: "samples", Unit: "count"}, - {Type: "cpu", Unit: "nanoseconds"}, - }, - } - var err error - if b, _, err = parseCPUSamples(b, parse, true, p); err != nil { - return nil, err - } - - // If *most* samples have the same second-to-the-bottom frame, it - // strongly suggests that it is an uninteresting artifact of - // measurement -- a stack frame pushed by the signal handler. The - // bottom frame is always correct as it is picked up from the signal - // structure, not the stack. Check if this is the case and if so, - // remove. - - // Remove up to two frames. - maxiter := 2 - // Allow one different sample for this many samples with the same - // second-to-last frame. - similarSamples := 32 - margin := len(p.Sample) / similarSamples - - for iter := 0; iter < maxiter; iter++ { - addr1 := make(map[uint64]int) - for _, s := range p.Sample { - if len(s.Location) > 1 { - a := s.Location[1].Address - addr1[a] = addr1[a] + 1 - } - } - - for id1, count := range addr1 { - if count >= len(p.Sample)-margin { - // Found uninteresting frame, strip it out from all samples - for _, s := range p.Sample { - if len(s.Location) > 1 && s.Location[1].Address == id1 { - s.Location = append(s.Location[:1], s.Location[2:]...) - } - } - break - } - } - } - - if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil { - return nil, err - } - - cleanupDuplicateLocations(p) - return p, nil -} - -func cleanupDuplicateLocations(p *Profile) { - // The profile handler may duplicate the leaf frame, because it gets - // its address both from stack unwinding and from the signal - // context. Detect this and delete the duplicate, which has been - // adjusted by -1. The leaf address should not be adjusted as it is - // not a call. - for _, s := range p.Sample { - if len(s.Location) > 1 && s.Location[0].Address == s.Location[1].Address+1 { - s.Location = append(s.Location[:1], s.Location[2:]...) - } - } -} - -// parseCPUSamples parses a collection of profilez samples from a -// profile. -// -// profilez samples are a repeated sequence of stack frames of the -// form: -// 1st word -- The number of times this stack was encountered. -// 2nd word -- The size of the stack (StackSize). -// 3rd word -- The first address on the stack. -// ... -// StackSize + 2 -- The last address on the stack -// The last stack trace is of the form: -// 1st word -- 0 -// 2nd word -- 1 -// 3rd word -- 0 -// -// Addresses from stack traces may point to the next instruction after -// each call. Optionally adjust by -1 to land somewhere on the actual -// call (except for the leaf, which is not a call). -func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) { - locs := make(map[uint64]*Location) - for len(b) > 0 { - var count, nstk uint64 - count, b = parse(b) - nstk, b = parse(b) - if b == nil || nstk > uint64(len(b)/4) { - return nil, nil, errUnrecognized - } - var sloc []*Location - addrs := make([]uint64, nstk) - for i := 0; i < int(nstk); i++ { - addrs[i], b = parse(b) - } - - if count == 0 && nstk == 1 && addrs[0] == 0 { - // End of data marker - break - } - for i, addr := range addrs { - if adjust && i > 0 { - addr-- - } - loc := locs[addr] - if loc == nil { - loc = &Location{ - Address: addr, - } - locs[addr] = loc - p.Location = append(p.Location, loc) - } - sloc = append(sloc, loc) - } - p.Sample = append(p.Sample, - &Sample{ - Value: []int64{int64(count), int64(count) * p.Period}, - Location: sloc, - }) - } - // Reached the end without finding the EOD marker. - return b, locs, nil -} - -// parseHeap parses a heapz legacy or a growthz profile and -// returns a newly populated Profile. -func parseHeap(b []byte) (p *Profile, err error) { - s := bufio.NewScanner(bytes.NewBuffer(b)) - if !s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - return nil, errUnrecognized - } - p = &Profile{} - - sampling := "" - hasAlloc := false - - line := s.Text() - p.PeriodType = &ValueType{Type: "space", Unit: "bytes"} - if header := heapHeaderRE.FindStringSubmatch(line); header != nil { - sampling, p.Period, hasAlloc, err = parseHeapHeader(line) - if err != nil { - return nil, err - } - } else if header = growthHeaderRE.FindStringSubmatch(line); header != nil { - p.Period = 1 - } else if header = fragmentationHeaderRE.FindStringSubmatch(line); header != nil { - p.Period = 1 - } else { - return nil, errUnrecognized - } - - if hasAlloc { - // Put alloc before inuse so that default pprof selection - // will prefer inuse_space. - p.SampleType = []*ValueType{ - {Type: "alloc_objects", Unit: "count"}, - {Type: "alloc_space", Unit: "bytes"}, - {Type: "inuse_objects", Unit: "count"}, - {Type: "inuse_space", Unit: "bytes"}, - } - } else { - p.SampleType = []*ValueType{ - {Type: "objects", Unit: "count"}, - {Type: "space", Unit: "bytes"}, - } - } - - locs := make(map[uint64]*Location) - for s.Scan() { - line := strings.TrimSpace(s.Text()) - - if isSpaceOrComment(line) { - continue - } - - if isMemoryMapSentinel(line) { - break - } - - value, blocksize, addrs, err := parseHeapSample(line, p.Period, sampling, hasAlloc) - if err != nil { - return nil, err - } - - var sloc []*Location - for _, addr := range addrs { - // Addresses from stack traces point to the next instruction after - // each call. Adjust by -1 to land somewhere on the actual call. - addr-- - loc := locs[addr] - if locs[addr] == nil { - loc = &Location{ - Address: addr, - } - p.Location = append(p.Location, loc) - locs[addr] = loc - } - sloc = append(sloc, loc) - } - - p.Sample = append(p.Sample, &Sample{ - Value: value, - Location: sloc, - NumLabel: map[string][]int64{"bytes": {blocksize}}, - }) - } - if err := s.Err(); err != nil { - return nil, err - } - if err := parseAdditionalSections(s, p); err != nil { - return nil, err - } - return p, nil -} - -func parseHeapHeader(line string) (sampling string, period int64, hasAlloc bool, err error) { - header := heapHeaderRE.FindStringSubmatch(line) - if header == nil { - return "", 0, false, errUnrecognized - } - - if len(header[6]) > 0 { - if period, err = strconv.ParseInt(header[6], 10, 64); err != nil { - return "", 0, false, errUnrecognized - } - } - - if (header[3] != header[1] && header[3] != "0") || (header[4] != header[2] && header[4] != "0") { - hasAlloc = true - } - - switch header[5] { - case "heapz_v2", "heap_v2": - return "v2", period, hasAlloc, nil - case "heapprofile": - return "", 1, hasAlloc, nil - case "heap": - return "v2", period / 2, hasAlloc, nil - default: - return "", 0, false, errUnrecognized - } -} - -// parseHeapSample parses a single row from a heap profile into a new Sample. -func parseHeapSample(line string, rate int64, sampling string, includeAlloc bool) (value []int64, blocksize int64, addrs []uint64, err error) { - sampleData := heapSampleRE.FindStringSubmatch(line) - if len(sampleData) != 6 { - return nil, 0, nil, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData)) - } - - // This is a local-scoped helper function to avoid needing to pass - // around rate, sampling and many return parameters. - addValues := func(countString, sizeString string, label string) error { - count, err := strconv.ParseInt(countString, 10, 64) - if err != nil { - return fmt.Errorf("malformed sample: %s: %v", line, err) - } - size, err := strconv.ParseInt(sizeString, 10, 64) - if err != nil { - return fmt.Errorf("malformed sample: %s: %v", line, err) - } - if count == 0 && size != 0 { - return fmt.Errorf("%s count was 0 but %s bytes was %d", label, label, size) - } - if count != 0 { - blocksize = size / count - if sampling == "v2" { - count, size = scaleHeapSample(count, size, rate) - } - } - value = append(value, count, size) - return nil - } - - if includeAlloc { - if err := addValues(sampleData[3], sampleData[4], "allocation"); err != nil { - return nil, 0, nil, err - } - } - - if err := addValues(sampleData[1], sampleData[2], "inuse"); err != nil { - return nil, 0, nil, err - } - - addrs, err = parseHexAddresses(sampleData[5]) - if err != nil { - return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - - return value, blocksize, addrs, nil -} - -// parseHexAddresses extracts hex numbers from a string, attempts to convert -// each to an unsigned 64-bit number and returns the resulting numbers as a -// slice, or an error if the string contains hex numbers which are too large to -// handle (which means a malformed profile). -func parseHexAddresses(s string) ([]uint64, error) { - hexStrings := hexNumberRE.FindAllString(s, -1) - var addrs []uint64 - for _, s := range hexStrings { - if addr, err := strconv.ParseUint(s, 0, 64); err == nil { - addrs = append(addrs, addr) - } else { - return nil, fmt.Errorf("failed to parse as hex 64-bit number: %s", s) - } - } - return addrs, nil -} - -// scaleHeapSample adjusts the data from a heapz Sample to -// account for its probability of appearing in the collected -// data. heapz profiles are a sampling of the memory allocations -// requests in a program. We estimate the unsampled value by dividing -// each collected sample by its probability of appearing in the -// profile. heapz v2 profiles rely on a poisson process to determine -// which samples to collect, based on the desired average collection -// rate R. The probability of a sample of size S to appear in that -// profile is 1-exp(-S/R). -func scaleHeapSample(count, size, rate int64) (int64, int64) { - if count == 0 || size == 0 { - return 0, 0 - } - - if rate <= 1 { - // if rate==1 all samples were collected so no adjustment is needed. - // if rate<1 treat as unknown and skip scaling. - return count, size - } - - avgSize := float64(size) / float64(count) - scale := 1 / (1 - math.Exp(-avgSize/float64(rate))) - - return int64(float64(count) * scale), int64(float64(size) * scale) -} - -// parseContention parses a mutex or contention profile. There are 2 cases: -// "--- contentionz " for legacy C++ profiles (and backwards compatibility) -// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime. -func parseContention(b []byte) (*Profile, error) { - s := bufio.NewScanner(bytes.NewBuffer(b)) - if !s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - return nil, errUnrecognized - } - - switch l := s.Text(); { - case strings.HasPrefix(l, "--- contentionz "): - case strings.HasPrefix(l, "--- mutex:"): - case strings.HasPrefix(l, "--- contention:"): - default: - return nil, errUnrecognized - } - - p := &Profile{ - PeriodType: &ValueType{Type: "contentions", Unit: "count"}, - Period: 1, - SampleType: []*ValueType{ - {Type: "contentions", Unit: "count"}, - {Type: "delay", Unit: "nanoseconds"}, - }, - } - - var cpuHz int64 - // Parse text of the form "attribute = value" before the samples. - const delimiter = "=" - for s.Scan() { - line := s.Text() - if line = strings.TrimSpace(line); isSpaceOrComment(line) { - continue - } - if strings.HasPrefix(line, "---") { - break - } - attr := strings.SplitN(line, delimiter, 2) - if len(attr) != 2 { - break - } - key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]) - var err error - switch key { - case "cycles/second": - if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil { - return nil, errUnrecognized - } - case "sampling period": - if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil { - return nil, errUnrecognized - } - case "ms since reset": - ms, err := strconv.ParseInt(val, 0, 64) - if err != nil { - return nil, errUnrecognized - } - p.DurationNanos = ms * 1000 * 1000 - case "format": - // CPP contentionz profiles don't have format. - return nil, errUnrecognized - case "resolution": - // CPP contentionz profiles don't have resolution. - return nil, errUnrecognized - case "discarded samples": - default: - return nil, errUnrecognized - } - } - if err := s.Err(); err != nil { - return nil, err - } - - locs := make(map[uint64]*Location) - for { - line := strings.TrimSpace(s.Text()) - if strings.HasPrefix(line, "---") { - break - } - if !isSpaceOrComment(line) { - value, addrs, err := parseContentionSample(line, p.Period, cpuHz) - if err != nil { - return nil, err - } - var sloc []*Location - for _, addr := range addrs { - // Addresses from stack traces point to the next instruction after - // each call. Adjust by -1 to land somewhere on the actual call. - addr-- - loc := locs[addr] - if locs[addr] == nil { - loc = &Location{ - Address: addr, - } - p.Location = append(p.Location, loc) - locs[addr] = loc - } - sloc = append(sloc, loc) - } - p.Sample = append(p.Sample, &Sample{ - Value: value, - Location: sloc, - }) - } - if !s.Scan() { - break - } - } - if err := s.Err(); err != nil { - return nil, err - } - - if err := parseAdditionalSections(s, p); err != nil { - return nil, err - } - - return p, nil -} - -// parseContentionSample parses a single row from a contention profile -// into a new Sample. -func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) { - sampleData := contentionSampleRE.FindStringSubmatch(line) - if sampleData == nil { - return nil, nil, errUnrecognized - } - - v1, err := strconv.ParseInt(sampleData[1], 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - v2, err := strconv.ParseInt(sampleData[2], 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - - // Unsample values if period and cpuHz are available. - // - Delays are scaled to cycles and then to nanoseconds. - // - Contentions are scaled to cycles. - if period > 0 { - if cpuHz > 0 { - cpuGHz := float64(cpuHz) / 1e9 - v1 = int64(float64(v1) * float64(period) / cpuGHz) - } - v2 = v2 * period - } - - value = []int64{v2, v1} - addrs, err = parseHexAddresses(sampleData[3]) - if err != nil { - return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - - return value, addrs, nil -} - -// parseThread parses a Threadz profile and returns a new Profile. -func parseThread(b []byte) (*Profile, error) { - s := bufio.NewScanner(bytes.NewBuffer(b)) - // Skip past comments and empty lines seeking a real header. - for s.Scan() && isSpaceOrComment(s.Text()) { - } - - line := s.Text() - if m := threadzStartRE.FindStringSubmatch(line); m != nil { - // Advance over initial comments until first stack trace. - for s.Scan() { - if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") { - break - } - } - } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { - return nil, errUnrecognized - } - - p := &Profile{ - SampleType: []*ValueType{{Type: "thread", Unit: "count"}}, - PeriodType: &ValueType{Type: "thread", Unit: "count"}, - Period: 1, - } - - locs := make(map[uint64]*Location) - // Recognize each thread and populate profile samples. - for !isMemoryMapSentinel(line) { - if strings.HasPrefix(line, "---- no stack trace for") { - line = "" - break - } - if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { - return nil, errUnrecognized - } - - var addrs []uint64 - var err error - line, addrs, err = parseThreadSample(s) - if err != nil { - return nil, err - } - if len(addrs) == 0 { - // We got a --same as previous threads--. Bump counters. - if len(p.Sample) > 0 { - s := p.Sample[len(p.Sample)-1] - s.Value[0]++ - } - continue - } - - var sloc []*Location - for i, addr := range addrs { - // Addresses from stack traces point to the next instruction after - // each call. Adjust by -1 to land somewhere on the actual call - // (except for the leaf, which is not a call). - if i > 0 { - addr-- - } - loc := locs[addr] - if locs[addr] == nil { - loc = &Location{ - Address: addr, - } - p.Location = append(p.Location, loc) - locs[addr] = loc - } - sloc = append(sloc, loc) - } - - p.Sample = append(p.Sample, &Sample{ - Value: []int64{1}, - Location: sloc, - }) - } - - if err := parseAdditionalSections(s, p); err != nil { - return nil, err - } - - cleanupDuplicateLocations(p) - return p, nil -} - -// parseThreadSample parses a symbolized or unsymbolized stack trace. -// Returns the first line after the traceback, the sample (or nil if -// it hits a 'same-as-previous' marker) and an error. -func parseThreadSample(s *bufio.Scanner) (nextl string, addrs []uint64, err error) { - var line string - sameAsPrevious := false - for s.Scan() { - line = strings.TrimSpace(s.Text()) - if line == "" { - continue - } - - if strings.HasPrefix(line, "---") { - break - } - if strings.Contains(line, "same as previous thread") { - sameAsPrevious = true - continue - } - - curAddrs, err := parseHexAddresses(line) - if err != nil { - return "", nil, fmt.Errorf("malformed sample: %s: %v", line, err) - } - addrs = append(addrs, curAddrs...) - } - if err := s.Err(); err != nil { - return "", nil, err - } - if sameAsPrevious { - return line, nil, nil - } - return line, addrs, nil -} - -// parseAdditionalSections parses any additional sections in the -// profile, ignoring any unrecognized sections. -func parseAdditionalSections(s *bufio.Scanner, p *Profile) error { - for !isMemoryMapSentinel(s.Text()) && s.Scan() { - } - if err := s.Err(); err != nil { - return err - } - return p.ParseMemoryMapFromScanner(s) -} - -// ParseProcMaps parses a memory map in the format of /proc/self/maps. -// ParseMemoryMap should be called after setting on a profile to -// associate locations to the corresponding mapping based on their -// address. -func ParseProcMaps(rd io.Reader) ([]*Mapping, error) { - s := bufio.NewScanner(rd) - return parseProcMapsFromScanner(s) -} - -func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) { - var mapping []*Mapping - - var attrs []string - const delimiter = "=" - r := strings.NewReplacer() - for s.Scan() { - line := r.Replace(removeLoggingInfo(s.Text())) - m, err := parseMappingEntry(line) - if err != nil { - if err == errUnrecognized { - // Recognize assignments of the form: attr=value, and replace - // $attr with value on subsequent mappings. - if attr := strings.SplitN(line, delimiter, 2); len(attr) == 2 { - attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])) - r = strings.NewReplacer(attrs...) - } - // Ignore any unrecognized entries - continue - } - return nil, err - } - if m == nil { - continue - } - mapping = append(mapping, m) - } - if err := s.Err(); err != nil { - return nil, err - } - return mapping, nil -} - -// removeLoggingInfo detects and removes log prefix entries generated -// by the glog package. If no logging prefix is detected, the string -// is returned unmodified. -func removeLoggingInfo(line string) string { - if match := logInfoRE.FindStringIndex(line); match != nil { - return line[match[1]:] - } - return line -} - -// ParseMemoryMap parses a memory map in the format of -// /proc/self/maps, and overrides the mappings in the current profile. -// It renumbers the samples and locations in the profile correspondingly. -func (p *Profile) ParseMemoryMap(rd io.Reader) error { - return p.ParseMemoryMapFromScanner(bufio.NewScanner(rd)) -} - -// ParseMemoryMapFromScanner parses a memory map in the format of -// /proc/self/maps or a variety of legacy format, and overrides the -// mappings in the current profile. It renumbers the samples and -// locations in the profile correspondingly. -func (p *Profile) ParseMemoryMapFromScanner(s *bufio.Scanner) error { - mapping, err := parseProcMapsFromScanner(s) - if err != nil { - return err - } - p.Mapping = append(p.Mapping, mapping...) - p.massageMappings() - p.remapLocationIDs() - p.remapFunctionIDs() - p.remapMappingIDs() - return nil -} - -func parseMappingEntry(l string) (*Mapping, error) { - var start, end, perm, file, offset, buildID string - if me := procMapsRE.FindStringSubmatch(l); len(me) == 6 { - start, end, perm, offset, file = me[1], me[2], me[3], me[4], me[5] - } else if me := briefMapsRE.FindStringSubmatch(l); len(me) == 7 { - start, end, perm, file, offset, buildID = me[1], me[2], me[3], me[4], me[5], me[6] - } else { - return nil, errUnrecognized - } - - var err error - mapping := &Mapping{ - File: file, - BuildID: buildID, - } - if perm != "" && !strings.Contains(perm, "x") { - // Skip non-executable entries. - return nil, nil - } - if mapping.Start, err = strconv.ParseUint(start, 16, 64); err != nil { - return nil, errUnrecognized - } - if mapping.Limit, err = strconv.ParseUint(end, 16, 64); err != nil { - return nil, errUnrecognized - } - if offset != "" { - if mapping.Offset, err = strconv.ParseUint(offset, 16, 64); err != nil { - return nil, errUnrecognized - } - } - return mapping, nil -} - -var memoryMapSentinels = []string{ - "--- Memory map: ---", - "MAPPED_LIBRARIES:", -} - -// isMemoryMapSentinel returns true if the string contains one of the -// known sentinels for memory map information. -func isMemoryMapSentinel(line string) bool { - for _, s := range memoryMapSentinels { - if strings.Contains(line, s) { - return true - } - } - return false -} - -func (p *Profile) addLegacyFrameInfo() { - switch { - case isProfileType(p, heapzSampleTypes): - p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr - case isProfileType(p, contentionzSampleTypes): - p.DropFrames, p.KeepFrames = lockRxStr, "" - default: - p.DropFrames, p.KeepFrames = cpuProfilerRxStr, "" - } -} - -var heapzSampleTypes = [][]string{ - {"allocations", "size"}, // early Go pprof profiles - {"objects", "space"}, - {"inuse_objects", "inuse_space"}, - {"alloc_objects", "alloc_space"}, - {"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles -} -var contentionzSampleTypes = [][]string{ - {"contentions", "delay"}, -} - -func isProfileType(p *Profile, types [][]string) bool { - st := p.SampleType -nextType: - for _, t := range types { - if len(st) != len(t) { - continue - } - - for i := range st { - if st[i].Type != t[i] { - continue nextType - } - } - return true - } - return false -} - -var allocRxStr = strings.Join([]string{ - // POSIX entry points. - `calloc`, - `cfree`, - `malloc`, - `free`, - `memalign`, - `do_memalign`, - `(__)?posix_memalign`, - `pvalloc`, - `valloc`, - `realloc`, - - // TC malloc. - `tcmalloc::.*`, - `tc_calloc`, - `tc_cfree`, - `tc_malloc`, - `tc_free`, - `tc_memalign`, - `tc_posix_memalign`, - `tc_pvalloc`, - `tc_valloc`, - `tc_realloc`, - `tc_new`, - `tc_delete`, - `tc_newarray`, - `tc_deletearray`, - `tc_new_nothrow`, - `tc_newarray_nothrow`, - - // Memory-allocation routines on OS X. - `malloc_zone_malloc`, - `malloc_zone_calloc`, - `malloc_zone_valloc`, - `malloc_zone_realloc`, - `malloc_zone_memalign`, - `malloc_zone_free`, - - // Go runtime - `runtime\..*`, - - // Other misc. memory allocation routines - `BaseArena::.*`, - `(::)?do_malloc_no_errno`, - `(::)?do_malloc_pages`, - `(::)?do_malloc`, - `DoSampledAllocation`, - `MallocedMemBlock::MallocedMemBlock`, - `_M_allocate`, - `__builtin_(vec_)?delete`, - `__builtin_(vec_)?new`, - `__gnu_cxx::new_allocator::allocate`, - `__libc_malloc`, - `__malloc_alloc_template::allocate`, - `allocate`, - `cpp_alloc`, - `operator new(\[\])?`, - `simple_alloc::allocate`, -}, `|`) - -var allocSkipRxStr = strings.Join([]string{ - // Preserve Go runtime frames that appear in the middle/bottom of - // the stack. - `runtime\.panic`, - `runtime\.reflectcall`, - `runtime\.call[0-9]*`, -}, `|`) - -var cpuProfilerRxStr = strings.Join([]string{ - `ProfileData::Add`, - `ProfileData::prof_handler`, - `CpuProfiler::prof_handler`, - `__pthread_sighandler`, - `__restore`, -}, `|`) - -var lockRxStr = strings.Join([]string{ - `RecordLockProfileData`, - `(base::)?RecordLockProfileData.*`, - `(base::)?SubmitMutexProfileData.*`, - `(base::)?SubmitSpinLockProfileData.*`, - `(base::Mutex::)?AwaitCommon.*`, - `(base::Mutex::)?Unlock.*`, - `(base::Mutex::)?UnlockSlow.*`, - `(base::Mutex::)?ReaderUnlock.*`, - `(base::MutexLock::)?~MutexLock.*`, - `(Mutex::)?AwaitCommon.*`, - `(Mutex::)?Unlock.*`, - `(Mutex::)?UnlockSlow.*`, - `(Mutex::)?ReaderUnlock.*`, - `(MutexLock::)?~MutexLock.*`, - `(SpinLock::)?Unlock.*`, - `(SpinLock::)?SlowUnlock.*`, - `(SpinLockHolder::)?~SpinLockHolder.*`, -}, `|`) diff --git a/vendor/github.com/google/pprof/profile/merge.go b/vendor/github.com/google/pprof/profile/merge.go deleted file mode 100644 index 9978e7330e..0000000000 --- a/vendor/github.com/google/pprof/profile/merge.go +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 profile - -import ( - "fmt" - "sort" - "strconv" - "strings" -) - -// Compact performs garbage collection on a profile to remove any -// unreferenced fields. This is useful to reduce the size of a profile -// after samples or locations have been removed. -func (p *Profile) Compact() *Profile { - p, _ = Merge([]*Profile{p}) - return p -} - -// Merge merges all the profiles in profs into a single Profile. -// Returns a new profile independent of the input profiles. The merged -// profile is compacted to eliminate unused samples, locations, -// functions and mappings. Profiles must have identical profile sample -// and period types or the merge will fail. profile.Period of the -// resulting profile will be the maximum of all profiles, and -// profile.TimeNanos will be the earliest nonzero one. Merges are -// associative with the caveat of the first profile having some -// specialization in how headers are combined. There may be other -// subtleties now or in the future regarding associativity. -func Merge(srcs []*Profile) (*Profile, error) { - if len(srcs) == 0 { - return nil, fmt.Errorf("no profiles to merge") - } - p, err := combineHeaders(srcs) - if err != nil { - return nil, err - } - - pm := &profileMerger{ - p: p, - samples: make(map[sampleKey]*Sample, len(srcs[0].Sample)), - locations: make(map[locationKey]*Location, len(srcs[0].Location)), - functions: make(map[functionKey]*Function, len(srcs[0].Function)), - mappings: make(map[mappingKey]*Mapping, len(srcs[0].Mapping)), - } - - for _, src := range srcs { - // Clear the profile-specific hash tables - pm.locationsByID = make(map[uint64]*Location, len(src.Location)) - pm.functionsByID = make(map[uint64]*Function, len(src.Function)) - pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping)) - - if len(pm.mappings) == 0 && len(src.Mapping) > 0 { - // The Mapping list has the property that the first mapping - // represents the main binary. Take the first Mapping we see, - // otherwise the operations below will add mappings in an - // arbitrary order. - pm.mapMapping(src.Mapping[0]) - } - - for _, s := range src.Sample { - if !isZeroSample(s) { - pm.mapSample(s) - } - } - } - - for _, s := range p.Sample { - if isZeroSample(s) { - // If there are any zero samples, re-merge the profile to GC - // them. - return Merge([]*Profile{p}) - } - } - - return p, nil -} - -// Normalize normalizes the source profile by multiplying each value in profile by the -// ratio of the sum of the base profile's values of that sample type to the sum of the -// source profile's value of that sample type. -func (p *Profile) Normalize(pb *Profile) error { - - if err := p.compatible(pb); err != nil { - return err - } - - baseVals := make([]int64, len(p.SampleType)) - for _, s := range pb.Sample { - for i, v := range s.Value { - baseVals[i] += v - } - } - - srcVals := make([]int64, len(p.SampleType)) - for _, s := range p.Sample { - for i, v := range s.Value { - srcVals[i] += v - } - } - - normScale := make([]float64, len(baseVals)) - for i := range baseVals { - if srcVals[i] == 0 { - normScale[i] = 0.0 - } else { - normScale[i] = float64(baseVals[i]) / float64(srcVals[i]) - } - } - p.ScaleN(normScale) - return nil -} - -func isZeroSample(s *Sample) bool { - for _, v := range s.Value { - if v != 0 { - return false - } - } - return true -} - -type profileMerger struct { - p *Profile - - // Memoization tables within a profile. - locationsByID map[uint64]*Location - functionsByID map[uint64]*Function - mappingsByID map[uint64]mapInfo - - // Memoization tables for profile entities. - samples map[sampleKey]*Sample - locations map[locationKey]*Location - functions map[functionKey]*Function - mappings map[mappingKey]*Mapping -} - -type mapInfo struct { - m *Mapping - offset int64 -} - -func (pm *profileMerger) mapSample(src *Sample) *Sample { - s := &Sample{ - Location: make([]*Location, len(src.Location)), - Value: make([]int64, len(src.Value)), - Label: make(map[string][]string, len(src.Label)), - NumLabel: make(map[string][]int64, len(src.NumLabel)), - NumUnit: make(map[string][]string, len(src.NumLabel)), - } - for i, l := range src.Location { - s.Location[i] = pm.mapLocation(l) - } - for k, v := range src.Label { - vv := make([]string, len(v)) - copy(vv, v) - s.Label[k] = vv - } - for k, v := range src.NumLabel { - u := src.NumUnit[k] - vv := make([]int64, len(v)) - uu := make([]string, len(u)) - copy(vv, v) - copy(uu, u) - s.NumLabel[k] = vv - s.NumUnit[k] = uu - } - // Check memoization table. Must be done on the remapped location to - // account for the remapped mapping. Add current values to the - // existing sample. - k := s.key() - if ss, ok := pm.samples[k]; ok { - for i, v := range src.Value { - ss.Value[i] += v - } - return ss - } - copy(s.Value, src.Value) - pm.samples[k] = s - pm.p.Sample = append(pm.p.Sample, s) - return s -} - -// key generates sampleKey to be used as a key for maps. -func (sample *Sample) key() sampleKey { - ids := make([]string, len(sample.Location)) - for i, l := range sample.Location { - ids[i] = strconv.FormatUint(l.ID, 16) - } - - labels := make([]string, 0, len(sample.Label)) - for k, v := range sample.Label { - labels = append(labels, fmt.Sprintf("%q%q", k, v)) - } - sort.Strings(labels) - - numlabels := make([]string, 0, len(sample.NumLabel)) - for k, v := range sample.NumLabel { - numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k])) - } - sort.Strings(numlabels) - - return sampleKey{ - strings.Join(ids, "|"), - strings.Join(labels, ""), - strings.Join(numlabels, ""), - } -} - -type sampleKey struct { - locations string - labels string - numlabels string -} - -func (pm *profileMerger) mapLocation(src *Location) *Location { - if src == nil { - return nil - } - - if l, ok := pm.locationsByID[src.ID]; ok { - return l - } - - mi := pm.mapMapping(src.Mapping) - l := &Location{ - ID: uint64(len(pm.p.Location) + 1), - Mapping: mi.m, - Address: uint64(int64(src.Address) + mi.offset), - Line: make([]Line, len(src.Line)), - IsFolded: src.IsFolded, - } - for i, ln := range src.Line { - l.Line[i] = pm.mapLine(ln) - } - // Check memoization table. Must be done on the remapped location to - // account for the remapped mapping ID. - k := l.key() - if ll, ok := pm.locations[k]; ok { - pm.locationsByID[src.ID] = ll - return ll - } - pm.locationsByID[src.ID] = l - pm.locations[k] = l - pm.p.Location = append(pm.p.Location, l) - return l -} - -// key generates locationKey to be used as a key for maps. -func (l *Location) key() locationKey { - key := locationKey{ - addr: l.Address, - isFolded: l.IsFolded, - } - if l.Mapping != nil { - // Normalizes address to handle address space randomization. - key.addr -= l.Mapping.Start - key.mappingID = l.Mapping.ID - } - lines := make([]string, len(l.Line)*2) - for i, line := range l.Line { - if line.Function != nil { - lines[i*2] = strconv.FormatUint(line.Function.ID, 16) - } - lines[i*2+1] = strconv.FormatInt(line.Line, 16) - } - key.lines = strings.Join(lines, "|") - return key -} - -type locationKey struct { - addr, mappingID uint64 - lines string - isFolded bool -} - -func (pm *profileMerger) mapMapping(src *Mapping) mapInfo { - if src == nil { - return mapInfo{} - } - - if mi, ok := pm.mappingsByID[src.ID]; ok { - return mi - } - - // Check memoization tables. - mk := src.key() - if m, ok := pm.mappings[mk]; ok { - mi := mapInfo{m, int64(m.Start) - int64(src.Start)} - pm.mappingsByID[src.ID] = mi - return mi - } - m := &Mapping{ - ID: uint64(len(pm.p.Mapping) + 1), - Start: src.Start, - Limit: src.Limit, - Offset: src.Offset, - File: src.File, - BuildID: src.BuildID, - HasFunctions: src.HasFunctions, - HasFilenames: src.HasFilenames, - HasLineNumbers: src.HasLineNumbers, - HasInlineFrames: src.HasInlineFrames, - } - pm.p.Mapping = append(pm.p.Mapping, m) - - // Update memoization tables. - pm.mappings[mk] = m - mi := mapInfo{m, 0} - pm.mappingsByID[src.ID] = mi - return mi -} - -// key generates encoded strings of Mapping to be used as a key for -// maps. -func (m *Mapping) key() mappingKey { - // Normalize addresses to handle address space randomization. - // Round up to next 4K boundary to avoid minor discrepancies. - const mapsizeRounding = 0x1000 - - size := m.Limit - m.Start - size = size + mapsizeRounding - 1 - size = size - (size % mapsizeRounding) - key := mappingKey{ - size: size, - offset: m.Offset, - } - - switch { - case m.BuildID != "": - key.buildIDOrFile = m.BuildID - case m.File != "": - key.buildIDOrFile = m.File - default: - // A mapping containing neither build ID nor file name is a fake mapping. A - // key with empty buildIDOrFile is used for fake mappings so that they are - // treated as the same mapping during merging. - } - return key -} - -type mappingKey struct { - size, offset uint64 - buildIDOrFile string -} - -func (pm *profileMerger) mapLine(src Line) Line { - ln := Line{ - Function: pm.mapFunction(src.Function), - Line: src.Line, - } - return ln -} - -func (pm *profileMerger) mapFunction(src *Function) *Function { - if src == nil { - return nil - } - if f, ok := pm.functionsByID[src.ID]; ok { - return f - } - k := src.key() - if f, ok := pm.functions[k]; ok { - pm.functionsByID[src.ID] = f - return f - } - f := &Function{ - ID: uint64(len(pm.p.Function) + 1), - Name: src.Name, - SystemName: src.SystemName, - Filename: src.Filename, - StartLine: src.StartLine, - } - pm.functions[k] = f - pm.functionsByID[src.ID] = f - pm.p.Function = append(pm.p.Function, f) - return f -} - -// key generates a struct to be used as a key for maps. -func (f *Function) key() functionKey { - return functionKey{ - f.StartLine, - f.Name, - f.SystemName, - f.Filename, - } -} - -type functionKey struct { - startLine int64 - name, systemName, fileName string -} - -// combineHeaders checks that all profiles can be merged and returns -// their combined profile. -func combineHeaders(srcs []*Profile) (*Profile, error) { - for _, s := range srcs[1:] { - if err := srcs[0].compatible(s); err != nil { - return nil, err - } - } - - var timeNanos, durationNanos, period int64 - var comments []string - seenComments := map[string]bool{} - var defaultSampleType string - for _, s := range srcs { - if timeNanos == 0 || s.TimeNanos < timeNanos { - timeNanos = s.TimeNanos - } - durationNanos += s.DurationNanos - if period == 0 || period < s.Period { - period = s.Period - } - for _, c := range s.Comments { - if seen := seenComments[c]; !seen { - comments = append(comments, c) - seenComments[c] = true - } - } - if defaultSampleType == "" { - defaultSampleType = s.DefaultSampleType - } - } - - p := &Profile{ - SampleType: make([]*ValueType, len(srcs[0].SampleType)), - - DropFrames: srcs[0].DropFrames, - KeepFrames: srcs[0].KeepFrames, - - TimeNanos: timeNanos, - DurationNanos: durationNanos, - PeriodType: srcs[0].PeriodType, - Period: period, - - Comments: comments, - DefaultSampleType: defaultSampleType, - } - copy(p.SampleType, srcs[0].SampleType) - return p, nil -} - -// compatible determines if two profiles can be compared/merged. -// returns nil if the profiles are compatible; otherwise an error with -// details on the incompatibility. -func (p *Profile) compatible(pb *Profile) error { - if !equalValueType(p.PeriodType, pb.PeriodType) { - return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType) - } - - if len(p.SampleType) != len(pb.SampleType) { - return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType) - } - - for i := range p.SampleType { - if !equalValueType(p.SampleType[i], pb.SampleType[i]) { - return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType) - } - } - return nil -} - -// equalValueType returns true if the two value types are semantically -// equal. It ignores the internal fields used during encode/decode. -func equalValueType(st1, st2 *ValueType) bool { - return st1.Type == st2.Type && st1.Unit == st2.Unit -} diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go deleted file mode 100644 index 2590c8ddb4..0000000000 --- a/vendor/github.com/google/pprof/profile/profile.go +++ /dev/null @@ -1,805 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 profile provides a representation of profile.proto and -// methods to encode/decode profiles in this format. -package profile - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "math" - "path/filepath" - "regexp" - "sort" - "strings" - "sync" - "time" -) - -// Profile is an in-memory representation of profile.proto. -type Profile struct { - SampleType []*ValueType - DefaultSampleType string - Sample []*Sample - Mapping []*Mapping - Location []*Location - Function []*Function - Comments []string - - DropFrames string - KeepFrames string - - TimeNanos int64 - DurationNanos int64 - PeriodType *ValueType - Period int64 - - // The following fields are modified during encoding and copying, - // so are protected by a Mutex. - encodeMu sync.Mutex - - commentX []int64 - dropFramesX int64 - keepFramesX int64 - stringTable []string - defaultSampleTypeX int64 -} - -// ValueType corresponds to Profile.ValueType -type ValueType struct { - Type string // cpu, wall, inuse_space, etc - Unit string // seconds, nanoseconds, bytes, etc - - typeX int64 - unitX int64 -} - -// Sample corresponds to Profile.Sample -type Sample struct { - Location []*Location - Value []int64 - Label map[string][]string - NumLabel map[string][]int64 - NumUnit map[string][]string - - locationIDX []uint64 - labelX []label -} - -// label corresponds to Profile.Label -type label struct { - keyX int64 - // Exactly one of the two following values must be set - strX int64 - numX int64 // Integer value for this label - // can be set if numX has value - unitX int64 -} - -// Mapping corresponds to Profile.Mapping -type Mapping struct { - ID uint64 - Start uint64 - Limit uint64 - Offset uint64 - File string - BuildID string - HasFunctions bool - HasFilenames bool - HasLineNumbers bool - HasInlineFrames bool - - fileX int64 - buildIDX int64 -} - -// Location corresponds to Profile.Location -type Location struct { - ID uint64 - Mapping *Mapping - Address uint64 - Line []Line - IsFolded bool - - mappingIDX uint64 -} - -// Line corresponds to Profile.Line -type Line struct { - Function *Function - Line int64 - - functionIDX uint64 -} - -// Function corresponds to Profile.Function -type Function struct { - ID uint64 - Name string - SystemName string - Filename string - StartLine int64 - - nameX int64 - systemNameX int64 - filenameX int64 -} - -// Parse parses a profile and checks for its validity. The input -// may be a gzip-compressed encoded protobuf or one of many legacy -// profile formats which may be unsupported in the future. -func Parse(r io.Reader) (*Profile, error) { - data, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - return ParseData(data) -} - -// ParseData parses a profile from a buffer and checks for its -// validity. -func ParseData(data []byte) (*Profile, error) { - var p *Profile - var err error - if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err == nil { - data, err = ioutil.ReadAll(gz) - } - if err != nil { - return nil, fmt.Errorf("decompressing profile: %v", err) - } - } - if p, err = ParseUncompressed(data); err != nil && err != errNoData && err != errConcatProfile { - p, err = parseLegacy(data) - } - - if err != nil { - return nil, fmt.Errorf("parsing profile: %v", err) - } - - if err := p.CheckValid(); err != nil { - return nil, fmt.Errorf("malformed profile: %v", err) - } - return p, nil -} - -var errUnrecognized = fmt.Errorf("unrecognized profile format") -var errMalformed = fmt.Errorf("malformed profile format") -var errNoData = fmt.Errorf("empty input file") -var errConcatProfile = fmt.Errorf("concatenated profiles detected") - -func parseLegacy(data []byte) (*Profile, error) { - parsers := []func([]byte) (*Profile, error){ - parseCPU, - parseHeap, - parseGoCount, // goroutine, threadcreate - parseThread, - parseContention, - parseJavaProfile, - } - - for _, parser := range parsers { - p, err := parser(data) - if err == nil { - p.addLegacyFrameInfo() - return p, nil - } - if err != errUnrecognized { - return nil, err - } - } - return nil, errUnrecognized -} - -// ParseUncompressed parses an uncompressed protobuf into a profile. -func ParseUncompressed(data []byte) (*Profile, error) { - if len(data) == 0 { - return nil, errNoData - } - p := &Profile{} - if err := unmarshal(data, p); err != nil { - return nil, err - } - - if err := p.postDecode(); err != nil { - return nil, err - } - - return p, nil -} - -var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`) - -// massageMappings applies heuristic-based changes to the profile -// mappings to account for quirks of some environments. -func (p *Profile) massageMappings() { - // Merge adjacent regions with matching names, checking that the offsets match - if len(p.Mapping) > 1 { - mappings := []*Mapping{p.Mapping[0]} - for _, m := range p.Mapping[1:] { - lm := mappings[len(mappings)-1] - if adjacent(lm, m) { - lm.Limit = m.Limit - if m.File != "" { - lm.File = m.File - } - if m.BuildID != "" { - lm.BuildID = m.BuildID - } - p.updateLocationMapping(m, lm) - continue - } - mappings = append(mappings, m) - } - p.Mapping = mappings - } - - // Use heuristics to identify main binary and move it to the top of the list of mappings - for i, m := range p.Mapping { - file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1)) - if len(file) == 0 { - continue - } - if len(libRx.FindStringSubmatch(file)) > 0 { - continue - } - if file[0] == '[' { - continue - } - // Swap what we guess is main to position 0. - p.Mapping[0], p.Mapping[i] = p.Mapping[i], p.Mapping[0] - break - } - - // Keep the mapping IDs neatly sorted - for i, m := range p.Mapping { - m.ID = uint64(i + 1) - } -} - -// adjacent returns whether two mapping entries represent the same -// mapping that has been split into two. Check that their addresses are adjacent, -// and if the offsets match, if they are available. -func adjacent(m1, m2 *Mapping) bool { - if m1.File != "" && m2.File != "" { - if m1.File != m2.File { - return false - } - } - if m1.BuildID != "" && m2.BuildID != "" { - if m1.BuildID != m2.BuildID { - return false - } - } - if m1.Limit != m2.Start { - return false - } - if m1.Offset != 0 && m2.Offset != 0 { - offset := m1.Offset + (m1.Limit - m1.Start) - if offset != m2.Offset { - return false - } - } - return true -} - -func (p *Profile) updateLocationMapping(from, to *Mapping) { - for _, l := range p.Location { - if l.Mapping == from { - l.Mapping = to - } - } -} - -func serialize(p *Profile) []byte { - p.encodeMu.Lock() - p.preEncode() - b := marshal(p) - p.encodeMu.Unlock() - return b -} - -// Write writes the profile as a gzip-compressed marshaled protobuf. -func (p *Profile) Write(w io.Writer) error { - zw := gzip.NewWriter(w) - defer zw.Close() - _, err := zw.Write(serialize(p)) - return err -} - -// WriteUncompressed writes the profile as a marshaled protobuf. -func (p *Profile) WriteUncompressed(w io.Writer) error { - _, err := w.Write(serialize(p)) - return err -} - -// CheckValid tests whether the profile is valid. Checks include, but are -// not limited to: -// - len(Profile.Sample[n].value) == len(Profile.value_unit) -// - Sample.id has a corresponding Profile.Location -func (p *Profile) CheckValid() error { - // Check that sample values are consistent - sampleLen := len(p.SampleType) - if sampleLen == 0 && len(p.Sample) != 0 { - return fmt.Errorf("missing sample type information") - } - for _, s := range p.Sample { - if s == nil { - return fmt.Errorf("profile has nil sample") - } - if len(s.Value) != sampleLen { - return fmt.Errorf("mismatch: sample has %d values vs. %d types", len(s.Value), len(p.SampleType)) - } - for _, l := range s.Location { - if l == nil { - return fmt.Errorf("sample has nil location") - } - } - } - - // Check that all mappings/locations/functions are in the tables - // Check that there are no duplicate ids - mappings := make(map[uint64]*Mapping, len(p.Mapping)) - for _, m := range p.Mapping { - if m == nil { - return fmt.Errorf("profile has nil mapping") - } - if m.ID == 0 { - return fmt.Errorf("found mapping with reserved ID=0") - } - if mappings[m.ID] != nil { - return fmt.Errorf("multiple mappings with same id: %d", m.ID) - } - mappings[m.ID] = m - } - functions := make(map[uint64]*Function, len(p.Function)) - for _, f := range p.Function { - if f == nil { - return fmt.Errorf("profile has nil function") - } - if f.ID == 0 { - return fmt.Errorf("found function with reserved ID=0") - } - if functions[f.ID] != nil { - return fmt.Errorf("multiple functions with same id: %d", f.ID) - } - functions[f.ID] = f - } - locations := make(map[uint64]*Location, len(p.Location)) - for _, l := range p.Location { - if l == nil { - return fmt.Errorf("profile has nil location") - } - if l.ID == 0 { - return fmt.Errorf("found location with reserved id=0") - } - if locations[l.ID] != nil { - return fmt.Errorf("multiple locations with same id: %d", l.ID) - } - locations[l.ID] = l - if m := l.Mapping; m != nil { - if m.ID == 0 || mappings[m.ID] != m { - return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID) - } - } - for _, ln := range l.Line { - f := ln.Function - if f == nil { - return fmt.Errorf("location id: %d has a line with nil function", l.ID) - } - if f.ID == 0 || functions[f.ID] != f { - return fmt.Errorf("inconsistent function %p: %d", f, f.ID) - } - } - } - return nil -} - -// Aggregate merges the locations in the profile into equivalence -// classes preserving the request attributes. It also updates the -// samples to point to the merged locations. -func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error { - for _, m := range p.Mapping { - m.HasInlineFrames = m.HasInlineFrames && inlineFrame - m.HasFunctions = m.HasFunctions && function - m.HasFilenames = m.HasFilenames && filename - m.HasLineNumbers = m.HasLineNumbers && linenumber - } - - // Aggregate functions - if !function || !filename { - for _, f := range p.Function { - if !function { - f.Name = "" - f.SystemName = "" - } - if !filename { - f.Filename = "" - } - } - } - - // Aggregate locations - if !inlineFrame || !address || !linenumber { - for _, l := range p.Location { - if !inlineFrame && len(l.Line) > 1 { - l.Line = l.Line[len(l.Line)-1:] - } - if !linenumber { - for i := range l.Line { - l.Line[i].Line = 0 - } - } - if !address { - l.Address = 0 - } - } - } - - return p.CheckValid() -} - -// NumLabelUnits returns a map of numeric label keys to the units -// associated with those keys and a map of those keys to any units -// that were encountered but not used. -// Unit for a given key is the first encountered unit for that key. If multiple -// units are encountered for values paired with a particular key, then the first -// unit encountered is used and all other units are returned in sorted order -// in map of ignored units. -// If no units are encountered for a particular key, the unit is then inferred -// based on the key. -func (p *Profile) NumLabelUnits() (map[string]string, map[string][]string) { - numLabelUnits := map[string]string{} - ignoredUnits := map[string]map[string]bool{} - encounteredKeys := map[string]bool{} - - // Determine units based on numeric tags for each sample. - for _, s := range p.Sample { - for k := range s.NumLabel { - encounteredKeys[k] = true - for _, unit := range s.NumUnit[k] { - if unit == "" { - continue - } - if wantUnit, ok := numLabelUnits[k]; !ok { - numLabelUnits[k] = unit - } else if wantUnit != unit { - if v, ok := ignoredUnits[k]; ok { - v[unit] = true - } else { - ignoredUnits[k] = map[string]bool{unit: true} - } - } - } - } - } - // Infer units for keys without any units associated with - // numeric tag values. - for key := range encounteredKeys { - unit := numLabelUnits[key] - if unit == "" { - switch key { - case "alignment", "request": - numLabelUnits[key] = "bytes" - default: - numLabelUnits[key] = key - } - } - } - - // Copy ignored units into more readable format - unitsIgnored := make(map[string][]string, len(ignoredUnits)) - for key, values := range ignoredUnits { - units := make([]string, len(values)) - i := 0 - for unit := range values { - units[i] = unit - i++ - } - sort.Strings(units) - unitsIgnored[key] = units - } - - return numLabelUnits, unitsIgnored -} - -// String dumps a text representation of a profile. Intended mainly -// for debugging purposes. -func (p *Profile) String() string { - ss := make([]string, 0, len(p.Comments)+len(p.Sample)+len(p.Mapping)+len(p.Location)) - for _, c := range p.Comments { - ss = append(ss, "Comment: "+c) - } - if pt := p.PeriodType; pt != nil { - ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit)) - } - ss = append(ss, fmt.Sprintf("Period: %d", p.Period)) - if p.TimeNanos != 0 { - ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos))) - } - if p.DurationNanos != 0 { - ss = append(ss, fmt.Sprintf("Duration: %.4v", time.Duration(p.DurationNanos))) - } - - ss = append(ss, "Samples:") - var sh1 string - for _, s := range p.SampleType { - dflt := "" - if s.Type == p.DefaultSampleType { - dflt = "[dflt]" - } - sh1 = sh1 + fmt.Sprintf("%s/%s%s ", s.Type, s.Unit, dflt) - } - ss = append(ss, strings.TrimSpace(sh1)) - for _, s := range p.Sample { - ss = append(ss, s.string()) - } - - ss = append(ss, "Locations") - for _, l := range p.Location { - ss = append(ss, l.string()) - } - - ss = append(ss, "Mappings") - for _, m := range p.Mapping { - ss = append(ss, m.string()) - } - - return strings.Join(ss, "\n") + "\n" -} - -// string dumps a text representation of a mapping. Intended mainly -// for debugging purposes. -func (m *Mapping) string() string { - bits := "" - if m.HasFunctions { - bits = bits + "[FN]" - } - if m.HasFilenames { - bits = bits + "[FL]" - } - if m.HasLineNumbers { - bits = bits + "[LN]" - } - if m.HasInlineFrames { - bits = bits + "[IN]" - } - return fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s", - m.ID, - m.Start, m.Limit, m.Offset, - m.File, - m.BuildID, - bits) -} - -// string dumps a text representation of a location. Intended mainly -// for debugging purposes. -func (l *Location) string() string { - ss := []string{} - locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address) - if m := l.Mapping; m != nil { - locStr = locStr + fmt.Sprintf("M=%d ", m.ID) - } - if l.IsFolded { - locStr = locStr + "[F] " - } - if len(l.Line) == 0 { - ss = append(ss, locStr) - } - for li := range l.Line { - lnStr := "??" - if fn := l.Line[li].Function; fn != nil { - lnStr = fmt.Sprintf("%s %s:%d s=%d", - fn.Name, - fn.Filename, - l.Line[li].Line, - fn.StartLine) - if fn.Name != fn.SystemName { - lnStr = lnStr + "(" + fn.SystemName + ")" - } - } - ss = append(ss, locStr+lnStr) - // Do not print location details past the first line - locStr = " " - } - return strings.Join(ss, "\n") -} - -// string dumps a text representation of a sample. Intended mainly -// for debugging purposes. -func (s *Sample) string() string { - ss := []string{} - var sv string - for _, v := range s.Value { - sv = fmt.Sprintf("%s %10d", sv, v) - } - sv = sv + ": " - for _, l := range s.Location { - sv = sv + fmt.Sprintf("%d ", l.ID) - } - ss = append(ss, sv) - const labelHeader = " " - if len(s.Label) > 0 { - ss = append(ss, labelHeader+labelsToString(s.Label)) - } - if len(s.NumLabel) > 0 { - ss = append(ss, labelHeader+numLabelsToString(s.NumLabel, s.NumUnit)) - } - return strings.Join(ss, "\n") -} - -// labelsToString returns a string representation of a -// map representing labels. -func labelsToString(labels map[string][]string) string { - ls := []string{} - for k, v := range labels { - ls = append(ls, fmt.Sprintf("%s:%v", k, v)) - } - sort.Strings(ls) - return strings.Join(ls, " ") -} - -// numLabelsToString returns a string representation of a map -// representing numeric labels. -func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]string) string { - ls := []string{} - for k, v := range numLabels { - units := numUnits[k] - var labelString string - if len(units) == len(v) { - values := make([]string, len(v)) - for i, vv := range v { - values[i] = fmt.Sprintf("%d %s", vv, units[i]) - } - labelString = fmt.Sprintf("%s:%v", k, values) - } else { - labelString = fmt.Sprintf("%s:%v", k, v) - } - ls = append(ls, labelString) - } - sort.Strings(ls) - return strings.Join(ls, " ") -} - -// SetLabel sets the specified key to the specified value for all samples in the -// profile. -func (p *Profile) SetLabel(key string, value []string) { - for _, sample := range p.Sample { - if sample.Label == nil { - sample.Label = map[string][]string{key: value} - } else { - sample.Label[key] = value - } - } -} - -// RemoveLabel removes all labels associated with the specified key for all -// samples in the profile. -func (p *Profile) RemoveLabel(key string) { - for _, sample := range p.Sample { - delete(sample.Label, key) - } -} - -// HasLabel returns true if a sample has a label with indicated key and value. -func (s *Sample) HasLabel(key, value string) bool { - for _, v := range s.Label[key] { - if v == value { - return true - } - } - return false -} - -// DiffBaseSample returns true if a sample belongs to the diff base and false -// otherwise. -func (s *Sample) DiffBaseSample() bool { - return s.HasLabel("pprof::base", "true") -} - -// Scale multiplies all sample values in a profile by a constant and keeps -// only samples that have at least one non-zero value. -func (p *Profile) Scale(ratio float64) { - if ratio == 1 { - return - } - ratios := make([]float64, len(p.SampleType)) - for i := range p.SampleType { - ratios[i] = ratio - } - p.ScaleN(ratios) -} - -// ScaleN multiplies each sample values in a sample by a different amount -// and keeps only samples that have at least one non-zero value. -func (p *Profile) ScaleN(ratios []float64) error { - if len(p.SampleType) != len(ratios) { - return fmt.Errorf("mismatched scale ratios, got %d, want %d", len(ratios), len(p.SampleType)) - } - allOnes := true - for _, r := range ratios { - if r != 1 { - allOnes = false - break - } - } - if allOnes { - return nil - } - fillIdx := 0 - for _, s := range p.Sample { - keepSample := false - for i, v := range s.Value { - if ratios[i] != 1 { - val := int64(math.Round(float64(v) * ratios[i])) - s.Value[i] = val - keepSample = keepSample || val != 0 - } - } - if keepSample { - p.Sample[fillIdx] = s - fillIdx++ - } - } - p.Sample = p.Sample[:fillIdx] - return nil -} - -// HasFunctions determines if all locations in this profile have -// symbolized function information. -func (p *Profile) HasFunctions() bool { - for _, l := range p.Location { - if l.Mapping != nil && !l.Mapping.HasFunctions { - return false - } - } - return true -} - -// HasFileLines determines if all locations in this profile have -// symbolized file and line number information. -func (p *Profile) HasFileLines() bool { - for _, l := range p.Location { - if l.Mapping != nil && (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) { - return false - } - } - return true -} - -// Unsymbolizable returns true if a mapping points to a binary for which -// locations can't be symbolized in principle, at least now. Examples are -// "[vdso]", [vsyscall]" and some others, see the code. -func (m *Mapping) Unsymbolizable() bool { - name := filepath.Base(m.File) - return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") -} - -// Copy makes a fully independent copy of a profile. -func (p *Profile) Copy() *Profile { - pp := &Profile{} - if err := unmarshal(serialize(p), pp); err != nil { - panic(err) - } - if err := pp.postDecode(); err != nil { - panic(err) - } - - return pp -} diff --git a/vendor/github.com/google/pprof/profile/proto.go b/vendor/github.com/google/pprof/profile/proto.go deleted file mode 100644 index 539ad3ab33..0000000000 --- a/vendor/github.com/google/pprof/profile/proto.go +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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. - -// This file is a simple protocol buffer encoder and decoder. -// The format is described at -// https://developers.google.com/protocol-buffers/docs/encoding -// -// A protocol message must implement the message interface: -// decoder() []decoder -// encode(*buffer) -// -// The decode method returns a slice indexed by field number that gives the -// function to decode that field. -// The encode method encodes its receiver into the given buffer. -// -// The two methods are simple enough to be implemented by hand rather than -// by using a protocol compiler. -// -// See profile.go for examples of messages implementing this interface. -// -// There is no support for groups, message sets, or "has" bits. - -package profile - -import ( - "errors" - "fmt" -) - -type buffer struct { - field int // field tag - typ int // proto wire type code for field - u64 uint64 - data []byte - tmp [16]byte -} - -type decoder func(*buffer, message) error - -type message interface { - decoder() []decoder - encode(*buffer) -} - -func marshal(m message) []byte { - var b buffer - m.encode(&b) - return b.data -} - -func encodeVarint(b *buffer, x uint64) { - for x >= 128 { - b.data = append(b.data, byte(x)|0x80) - x >>= 7 - } - b.data = append(b.data, byte(x)) -} - -func encodeLength(b *buffer, tag int, len int) { - encodeVarint(b, uint64(tag)<<3|2) - encodeVarint(b, uint64(len)) -} - -func encodeUint64(b *buffer, tag int, x uint64) { - // append varint to b.data - encodeVarint(b, uint64(tag)<<3) - encodeVarint(b, x) -} - -func encodeUint64s(b *buffer, tag int, x []uint64) { - if len(x) > 2 { - // Use packed encoding - n1 := len(b.data) - for _, u := range x { - encodeVarint(b, u) - } - n2 := len(b.data) - encodeLength(b, tag, n2-n1) - n3 := len(b.data) - copy(b.tmp[:], b.data[n2:n3]) - copy(b.data[n1+(n3-n2):], b.data[n1:n2]) - copy(b.data[n1:], b.tmp[:n3-n2]) - return - } - for _, u := range x { - encodeUint64(b, tag, u) - } -} - -func encodeUint64Opt(b *buffer, tag int, x uint64) { - if x == 0 { - return - } - encodeUint64(b, tag, x) -} - -func encodeInt64(b *buffer, tag int, x int64) { - u := uint64(x) - encodeUint64(b, tag, u) -} - -func encodeInt64s(b *buffer, tag int, x []int64) { - if len(x) > 2 { - // Use packed encoding - n1 := len(b.data) - for _, u := range x { - encodeVarint(b, uint64(u)) - } - n2 := len(b.data) - encodeLength(b, tag, n2-n1) - n3 := len(b.data) - copy(b.tmp[:], b.data[n2:n3]) - copy(b.data[n1+(n3-n2):], b.data[n1:n2]) - copy(b.data[n1:], b.tmp[:n3-n2]) - return - } - for _, u := range x { - encodeInt64(b, tag, u) - } -} - -func encodeInt64Opt(b *buffer, tag int, x int64) { - if x == 0 { - return - } - encodeInt64(b, tag, x) -} - -func encodeString(b *buffer, tag int, x string) { - encodeLength(b, tag, len(x)) - b.data = append(b.data, x...) -} - -func encodeStrings(b *buffer, tag int, x []string) { - for _, s := range x { - encodeString(b, tag, s) - } -} - -func encodeBool(b *buffer, tag int, x bool) { - if x { - encodeUint64(b, tag, 1) - } else { - encodeUint64(b, tag, 0) - } -} - -func encodeBoolOpt(b *buffer, tag int, x bool) { - if x { - encodeBool(b, tag, x) - } -} - -func encodeMessage(b *buffer, tag int, m message) { - n1 := len(b.data) - m.encode(b) - n2 := len(b.data) - encodeLength(b, tag, n2-n1) - n3 := len(b.data) - copy(b.tmp[:], b.data[n2:n3]) - copy(b.data[n1+(n3-n2):], b.data[n1:n2]) - copy(b.data[n1:], b.tmp[:n3-n2]) -} - -func unmarshal(data []byte, m message) (err error) { - b := buffer{data: data, typ: 2} - return decodeMessage(&b, m) -} - -func le64(p []byte) uint64 { - return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 -} - -func le32(p []byte) uint32 { - return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 -} - -func decodeVarint(data []byte) (uint64, []byte, error) { - var u uint64 - for i := 0; ; i++ { - if i >= 10 || i >= len(data) { - return 0, nil, errors.New("bad varint") - } - u |= uint64(data[i]&0x7F) << uint(7*i) - if data[i]&0x80 == 0 { - return u, data[i+1:], nil - } - } -} - -func decodeField(b *buffer, data []byte) ([]byte, error) { - x, data, err := decodeVarint(data) - if err != nil { - return nil, err - } - b.field = int(x >> 3) - b.typ = int(x & 7) - b.data = nil - b.u64 = 0 - switch b.typ { - case 0: - b.u64, data, err = decodeVarint(data) - if err != nil { - return nil, err - } - case 1: - if len(data) < 8 { - return nil, errors.New("not enough data") - } - b.u64 = le64(data[:8]) - data = data[8:] - case 2: - var n uint64 - n, data, err = decodeVarint(data) - if err != nil { - return nil, err - } - if n > uint64(len(data)) { - return nil, errors.New("too much data") - } - b.data = data[:n] - data = data[n:] - case 5: - if len(data) < 4 { - return nil, errors.New("not enough data") - } - b.u64 = uint64(le32(data[:4])) - data = data[4:] - default: - return nil, fmt.Errorf("unknown wire type: %d", b.typ) - } - - return data, nil -} - -func checkType(b *buffer, typ int) error { - if b.typ != typ { - return errors.New("type mismatch") - } - return nil -} - -func decodeMessage(b *buffer, m message) error { - if err := checkType(b, 2); err != nil { - return err - } - dec := m.decoder() - data := b.data - for len(data) > 0 { - // pull varint field# + type - var err error - data, err = decodeField(b, data) - if err != nil { - return err - } - if b.field >= len(dec) || dec[b.field] == nil { - continue - } - if err := dec[b.field](b, m); err != nil { - return err - } - } - return nil -} - -func decodeInt64(b *buffer, x *int64) error { - if err := checkType(b, 0); err != nil { - return err - } - *x = int64(b.u64) - return nil -} - -func decodeInt64s(b *buffer, x *[]int64) error { - if b.typ == 2 { - // Packed encoding - data := b.data - tmp := make([]int64, 0, len(data)) // Maximally sized - for len(data) > 0 { - var u uint64 - var err error - - if u, data, err = decodeVarint(data); err != nil { - return err - } - tmp = append(tmp, int64(u)) - } - *x = append(*x, tmp...) - return nil - } - var i int64 - if err := decodeInt64(b, &i); err != nil { - return err - } - *x = append(*x, i) - return nil -} - -func decodeUint64(b *buffer, x *uint64) error { - if err := checkType(b, 0); err != nil { - return err - } - *x = b.u64 - return nil -} - -func decodeUint64s(b *buffer, x *[]uint64) error { - if b.typ == 2 { - data := b.data - // Packed encoding - tmp := make([]uint64, 0, len(data)) // Maximally sized - for len(data) > 0 { - var u uint64 - var err error - - if u, data, err = decodeVarint(data); err != nil { - return err - } - tmp = append(tmp, u) - } - *x = append(*x, tmp...) - return nil - } - var u uint64 - if err := decodeUint64(b, &u); err != nil { - return err - } - *x = append(*x, u) - return nil -} - -func decodeString(b *buffer, x *string) error { - if err := checkType(b, 2); err != nil { - return err - } - *x = string(b.data) - return nil -} - -func decodeStrings(b *buffer, x *[]string) error { - var s string - if err := decodeString(b, &s); err != nil { - return err - } - *x = append(*x, s) - return nil -} - -func decodeBool(b *buffer, x *bool) error { - if err := checkType(b, 0); err != nil { - return err - } - if int64(b.u64) == 0 { - *x = false - } else { - *x = true - } - return nil -} diff --git a/vendor/github.com/google/pprof/profile/prune.go b/vendor/github.com/google/pprof/profile/prune.go deleted file mode 100644 index 02d21a8184..0000000000 --- a/vendor/github.com/google/pprof/profile/prune.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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. - -// Implements methods to remove frames from profiles. - -package profile - -import ( - "fmt" - "regexp" - "strings" -) - -var ( - reservedNames = []string{"(anonymous namespace)", "operator()"} - bracketRx = func() *regexp.Regexp { - var quotedNames []string - for _, name := range append(reservedNames, "(") { - quotedNames = append(quotedNames, regexp.QuoteMeta(name)) - } - return regexp.MustCompile(strings.Join(quotedNames, "|")) - }() -) - -// simplifyFunc does some primitive simplification of function names. -func simplifyFunc(f string) string { - // Account for leading '.' on the PPC ELF v1 ABI. - funcName := strings.TrimPrefix(f, ".") - // Account for unsimplified names -- try to remove the argument list by trimming - // starting from the first '(', but skipping reserved names that have '('. - for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) { - foundReserved := false - for _, res := range reservedNames { - if funcName[ind[0]:ind[1]] == res { - foundReserved = true - break - } - } - if !foundReserved { - funcName = funcName[:ind[0]] - break - } - } - return funcName -} - -// Prune removes all nodes beneath a node matching dropRx, and not -// matching keepRx. If the root node of a Sample matches, the sample -// will have an empty stack. -func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) { - prune := make(map[uint64]bool) - pruneBeneath := make(map[uint64]bool) - - for _, loc := range p.Location { - var i int - for i = len(loc.Line) - 1; i >= 0; i-- { - if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { - funcName := simplifyFunc(fn.Name) - if dropRx.MatchString(funcName) { - if keepRx == nil || !keepRx.MatchString(funcName) { - break - } - } - } - } - - if i >= 0 { - // Found matching entry to prune. - pruneBeneath[loc.ID] = true - - // Remove the matching location. - if i == len(loc.Line)-1 { - // Matched the top entry: prune the whole location. - prune[loc.ID] = true - } else { - loc.Line = loc.Line[i+1:] - } - } - } - - // Prune locs from each Sample - for _, sample := range p.Sample { - // Scan from the root to the leaves to find the prune location. - // Do not prune frames before the first user frame, to avoid - // pruning everything. - foundUser := false - for i := len(sample.Location) - 1; i >= 0; i-- { - id := sample.Location[i].ID - if !prune[id] && !pruneBeneath[id] { - foundUser = true - continue - } - if !foundUser { - continue - } - if prune[id] { - sample.Location = sample.Location[i+1:] - break - } - if pruneBeneath[id] { - sample.Location = sample.Location[i:] - break - } - } - } -} - -// RemoveUninteresting prunes and elides profiles using built-in -// tables of uninteresting function names. -func (p *Profile) RemoveUninteresting() error { - var keep, drop *regexp.Regexp - var err error - - if p.DropFrames != "" { - if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil { - return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err) - } - if p.KeepFrames != "" { - if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil { - return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err) - } - } - p.Prune(drop, keep) - } - return nil -} - -// PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself. -// -// Please see the example below to understand this method as well as -// the difference from Prune method. -// -// A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline. -// -// PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A. -// Prune(A, nil) returns [B,C,B,D] by removing A itself. -// -// PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom. -// Prune(B, nil) returns [D] because a matching node is found by scanning from the root. -func (p *Profile) PruneFrom(dropRx *regexp.Regexp) { - pruneBeneath := make(map[uint64]bool) - - for _, loc := range p.Location { - for i := 0; i < len(loc.Line); i++ { - if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { - funcName := simplifyFunc(fn.Name) - if dropRx.MatchString(funcName) { - // Found matching entry to prune. - pruneBeneath[loc.ID] = true - loc.Line = loc.Line[i:] - break - } - } - } - } - - // Prune locs from each Sample - for _, sample := range p.Sample { - // Scan from the bottom leaf to the root to find the prune location. - for i, loc := range sample.Location { - if pruneBeneath[loc.ID] { - sample.Location = sample.Location[i:] - break - } - } - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/LICENSE b/vendor/github.com/onsi/ginkgo/v2/LICENSE deleted file mode 100644 index 9415ee72c1..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2013-2014 Onsi Fakhouri - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go b/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go deleted file mode 100644 index a61021d088..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go +++ /dev/null @@ -1,69 +0,0 @@ -package config - -// GinkgoConfigType has been deprecated and its equivalent now lives in -// the types package. You can no longer access Ginkgo configuration from the config -// package. Instead use the DSL's GinkgoConfiguration() function to get copies of the -// current configuration -// -// GinkgoConfigType is still here so custom V1 reporters do not result in a compilation error -// It will be removed in a future minor release of Ginkgo -type GinkgoConfigType = DeprecatedGinkgoConfigType -type DeprecatedGinkgoConfigType struct { - RandomSeed int64 - RandomizeAllSpecs bool - RegexScansFilePath bool - FocusStrings []string - SkipStrings []string - SkipMeasurements bool - FailOnPending bool - FailFast bool - FlakeAttempts int - EmitSpecProgress bool - DryRun bool - DebugParallel bool - - ParallelNode int - ParallelTotal int - SyncHost string - StreamHost string -} - -// DefaultReporterConfigType has been deprecated and its equivalent now lives in -// the types package. You can no longer access Ginkgo configuration from the config -// package. Instead use the DSL's GinkgoConfiguration() function to get copies of the -// current configuration -// -// DefaultReporterConfigType is still here so custom V1 reporters do not result in a compilation error -// It will be removed in a future minor release of Ginkgo -type DefaultReporterConfigType = DeprecatedDefaultReporterConfigType -type DeprecatedDefaultReporterConfigType struct { - NoColor bool - SlowSpecThreshold float64 - NoisyPendings bool - NoisySkippings bool - Succinct bool - Verbose bool - FullTrace bool - ReportPassed bool - ReportFile string -} - -// Sadly there is no way to gracefully deprecate access to these global config variables. -// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method -// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails -type GinkgoConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead struct{} - -// Sadly there is no way to gracefully deprecate access to these global config variables. -// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method -// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails -var GinkgoConfig = GinkgoConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead{} - -// Sadly there is no way to gracefully deprecate access to these global config variables. -// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method -// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails -type DefaultReporterConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead struct{} - -// Sadly there is no way to gracefully deprecate access to these global config variables. -// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method -// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails -var DefaultReporterConfig = DefaultReporterConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead{} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go deleted file mode 100644 index 778bfd7c7c..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go +++ /dev/null @@ -1,41 +0,0 @@ -// +build !windows - -/* -These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com - - * go-colorable: - * go-isatty: - -The MIT License (MIT) - -Copyright (c) 2016 Yasuhiro Matsumoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package formatter - -import ( - "io" - "os" -) - -func newColorable(file *os.File) io.Writer { - return file -} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go deleted file mode 100644 index dd1d143cc2..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go +++ /dev/null @@ -1,809 +0,0 @@ -/* -These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com - - * go-colorable: - * go-isatty: - -The MIT License (MIT) - -Copyright (c) 2016 Yasuhiro Matsumoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package formatter - -import ( - "bytes" - "fmt" - "io" - "math" - "os" - "strconv" - "strings" - "syscall" - "unsafe" -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") - procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") - procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -func isTerminal(fd uintptr) bool { - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -} - -const ( - foregroundBlue = 0x1 - foregroundGreen = 0x2 - foregroundRed = 0x4 - foregroundIntensity = 0x8 - foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) - backgroundBlue = 0x10 - backgroundGreen = 0x20 - backgroundRed = 0x40 - backgroundIntensity = 0x80 - backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) -) - -type wchar uint16 -type short int16 -type dword uint32 -type word uint16 - -type coord struct { - x short - y short -} - -type smallRect struct { - left short - top short - right short - bottom short -} - -type consoleScreenBufferInfo struct { - size coord - cursorPosition coord - attributes word - window smallRect - maximumWindowSize coord -} - -type writer struct { - out io.Writer - handle syscall.Handle - lastbuf bytes.Buffer - oldattr word -} - -func newColorable(file *os.File) io.Writer { - if file == nil { - panic("nil passed instead of *os.File to NewColorable()") - } - - if isTerminal(file.Fd()) { - var csbi consoleScreenBufferInfo - handle := syscall.Handle(file.Fd()) - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - return &writer{out: file, handle: handle, oldattr: csbi.attributes} - } else { - return file - } -} - -var color256 = map[int]int{ - 0: 0x000000, - 1: 0x800000, - 2: 0x008000, - 3: 0x808000, - 4: 0x000080, - 5: 0x800080, - 6: 0x008080, - 7: 0xc0c0c0, - 8: 0x808080, - 9: 0xff0000, - 10: 0x00ff00, - 11: 0xffff00, - 12: 0x0000ff, - 13: 0xff00ff, - 14: 0x00ffff, - 15: 0xffffff, - 16: 0x000000, - 17: 0x00005f, - 18: 0x000087, - 19: 0x0000af, - 20: 0x0000d7, - 21: 0x0000ff, - 22: 0x005f00, - 23: 0x005f5f, - 24: 0x005f87, - 25: 0x005faf, - 26: 0x005fd7, - 27: 0x005fff, - 28: 0x008700, - 29: 0x00875f, - 30: 0x008787, - 31: 0x0087af, - 32: 0x0087d7, - 33: 0x0087ff, - 34: 0x00af00, - 35: 0x00af5f, - 36: 0x00af87, - 37: 0x00afaf, - 38: 0x00afd7, - 39: 0x00afff, - 40: 0x00d700, - 41: 0x00d75f, - 42: 0x00d787, - 43: 0x00d7af, - 44: 0x00d7d7, - 45: 0x00d7ff, - 46: 0x00ff00, - 47: 0x00ff5f, - 48: 0x00ff87, - 49: 0x00ffaf, - 50: 0x00ffd7, - 51: 0x00ffff, - 52: 0x5f0000, - 53: 0x5f005f, - 54: 0x5f0087, - 55: 0x5f00af, - 56: 0x5f00d7, - 57: 0x5f00ff, - 58: 0x5f5f00, - 59: 0x5f5f5f, - 60: 0x5f5f87, - 61: 0x5f5faf, - 62: 0x5f5fd7, - 63: 0x5f5fff, - 64: 0x5f8700, - 65: 0x5f875f, - 66: 0x5f8787, - 67: 0x5f87af, - 68: 0x5f87d7, - 69: 0x5f87ff, - 70: 0x5faf00, - 71: 0x5faf5f, - 72: 0x5faf87, - 73: 0x5fafaf, - 74: 0x5fafd7, - 75: 0x5fafff, - 76: 0x5fd700, - 77: 0x5fd75f, - 78: 0x5fd787, - 79: 0x5fd7af, - 80: 0x5fd7d7, - 81: 0x5fd7ff, - 82: 0x5fff00, - 83: 0x5fff5f, - 84: 0x5fff87, - 85: 0x5fffaf, - 86: 0x5fffd7, - 87: 0x5fffff, - 88: 0x870000, - 89: 0x87005f, - 90: 0x870087, - 91: 0x8700af, - 92: 0x8700d7, - 93: 0x8700ff, - 94: 0x875f00, - 95: 0x875f5f, - 96: 0x875f87, - 97: 0x875faf, - 98: 0x875fd7, - 99: 0x875fff, - 100: 0x878700, - 101: 0x87875f, - 102: 0x878787, - 103: 0x8787af, - 104: 0x8787d7, - 105: 0x8787ff, - 106: 0x87af00, - 107: 0x87af5f, - 108: 0x87af87, - 109: 0x87afaf, - 110: 0x87afd7, - 111: 0x87afff, - 112: 0x87d700, - 113: 0x87d75f, - 114: 0x87d787, - 115: 0x87d7af, - 116: 0x87d7d7, - 117: 0x87d7ff, - 118: 0x87ff00, - 119: 0x87ff5f, - 120: 0x87ff87, - 121: 0x87ffaf, - 122: 0x87ffd7, - 123: 0x87ffff, - 124: 0xaf0000, - 125: 0xaf005f, - 126: 0xaf0087, - 127: 0xaf00af, - 128: 0xaf00d7, - 129: 0xaf00ff, - 130: 0xaf5f00, - 131: 0xaf5f5f, - 132: 0xaf5f87, - 133: 0xaf5faf, - 134: 0xaf5fd7, - 135: 0xaf5fff, - 136: 0xaf8700, - 137: 0xaf875f, - 138: 0xaf8787, - 139: 0xaf87af, - 140: 0xaf87d7, - 141: 0xaf87ff, - 142: 0xafaf00, - 143: 0xafaf5f, - 144: 0xafaf87, - 145: 0xafafaf, - 146: 0xafafd7, - 147: 0xafafff, - 148: 0xafd700, - 149: 0xafd75f, - 150: 0xafd787, - 151: 0xafd7af, - 152: 0xafd7d7, - 153: 0xafd7ff, - 154: 0xafff00, - 155: 0xafff5f, - 156: 0xafff87, - 157: 0xafffaf, - 158: 0xafffd7, - 159: 0xafffff, - 160: 0xd70000, - 161: 0xd7005f, - 162: 0xd70087, - 163: 0xd700af, - 164: 0xd700d7, - 165: 0xd700ff, - 166: 0xd75f00, - 167: 0xd75f5f, - 168: 0xd75f87, - 169: 0xd75faf, - 170: 0xd75fd7, - 171: 0xd75fff, - 172: 0xd78700, - 173: 0xd7875f, - 174: 0xd78787, - 175: 0xd787af, - 176: 0xd787d7, - 177: 0xd787ff, - 178: 0xd7af00, - 179: 0xd7af5f, - 180: 0xd7af87, - 181: 0xd7afaf, - 182: 0xd7afd7, - 183: 0xd7afff, - 184: 0xd7d700, - 185: 0xd7d75f, - 186: 0xd7d787, - 187: 0xd7d7af, - 188: 0xd7d7d7, - 189: 0xd7d7ff, - 190: 0xd7ff00, - 191: 0xd7ff5f, - 192: 0xd7ff87, - 193: 0xd7ffaf, - 194: 0xd7ffd7, - 195: 0xd7ffff, - 196: 0xff0000, - 197: 0xff005f, - 198: 0xff0087, - 199: 0xff00af, - 200: 0xff00d7, - 201: 0xff00ff, - 202: 0xff5f00, - 203: 0xff5f5f, - 204: 0xff5f87, - 205: 0xff5faf, - 206: 0xff5fd7, - 207: 0xff5fff, - 208: 0xff8700, - 209: 0xff875f, - 210: 0xff8787, - 211: 0xff87af, - 212: 0xff87d7, - 213: 0xff87ff, - 214: 0xffaf00, - 215: 0xffaf5f, - 216: 0xffaf87, - 217: 0xffafaf, - 218: 0xffafd7, - 219: 0xffafff, - 220: 0xffd700, - 221: 0xffd75f, - 222: 0xffd787, - 223: 0xffd7af, - 224: 0xffd7d7, - 225: 0xffd7ff, - 226: 0xffff00, - 227: 0xffff5f, - 228: 0xffff87, - 229: 0xffffaf, - 230: 0xffffd7, - 231: 0xffffff, - 232: 0x080808, - 233: 0x121212, - 234: 0x1c1c1c, - 235: 0x262626, - 236: 0x303030, - 237: 0x3a3a3a, - 238: 0x444444, - 239: 0x4e4e4e, - 240: 0x585858, - 241: 0x626262, - 242: 0x6c6c6c, - 243: 0x767676, - 244: 0x808080, - 245: 0x8a8a8a, - 246: 0x949494, - 247: 0x9e9e9e, - 248: 0xa8a8a8, - 249: 0xb2b2b2, - 250: 0xbcbcbc, - 251: 0xc6c6c6, - 252: 0xd0d0d0, - 253: 0xdadada, - 254: 0xe4e4e4, - 255: 0xeeeeee, -} - -func (w *writer) Write(data []byte) (n int, err error) { - var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - - er := bytes.NewBuffer(data) -loop: - for { - r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - if r1 == 0 { - break loop - } - - c1, _, err := er.ReadRune() - if err != nil { - break loop - } - if c1 != 0x1b { - fmt.Fprint(w.out, string(c1)) - continue - } - c2, _, err := er.ReadRune() - if err != nil { - w.lastbuf.WriteRune(c1) - break loop - } - if c2 != 0x5b { - w.lastbuf.WriteRune(c1) - w.lastbuf.WriteRune(c2) - continue - } - - var buf bytes.Buffer - var m rune - for { - c, _, err := er.ReadRune() - if err != nil { - w.lastbuf.WriteRune(c1) - w.lastbuf.WriteRune(c2) - w.lastbuf.Write(buf.Bytes()) - break loop - } - if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { - m = c - break - } - buf.Write([]byte(string(c))) - } - - var csbi consoleScreenBufferInfo - switch m { - case 'A': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'B': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'C': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'D': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - if n, err = strconv.Atoi(buf.String()); err == nil { - var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - } - case 'E': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = 0 - csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'F': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = 0 - csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'G': - n, err = strconv.Atoi(buf.String()) - if err != nil { - continue - } - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'H': - token := strings.Split(buf.String(), ";") - if len(token) != 2 { - continue - } - n1, err := strconv.Atoi(token[0]) - if err != nil { - continue - } - n2, err := strconv.Atoi(token[1]) - if err != nil { - continue - } - csbi.cursorPosition.x = short(n2) - csbi.cursorPosition.x = short(n1) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'J': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue - } - var cursor coord - switch n { - case 0: - cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top} - case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top} - } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - case 'K': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue - } - var cursor coord - switch n { - case 0: - cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - case 1: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} - case 2: - cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} - } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x) - procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - case 'm': - attr := csbi.attributes - cs := buf.String() - if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) - continue - } - token := strings.Split(cs, ";") - for i := 0; i < len(token); i += 1 { - ns := token[i] - if n, err = strconv.Atoi(ns); err == nil { - switch { - case n == 0 || n == 100: - attr = w.oldattr - case 1 <= n && n <= 5: - attr |= foregroundIntensity - case n == 7: - attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case 22 == n || n == 25 || n == 25: - attr |= foregroundIntensity - case n == 27: - attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case 30 <= n && n <= 37: - attr = (attr & backgroundMask) - if (n-30)&1 != 0 { - attr |= foregroundRed - } - if (n-30)&2 != 0 { - attr |= foregroundGreen - } - if (n-30)&4 != 0 { - attr |= foregroundBlue - } - case n == 38: // set foreground color. - if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { - if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256foreAttr == nil { - n256setup() - } - attr &= backgroundMask - attr |= n256foreAttr[n256] - i += 2 - } - } else { - attr = attr & (w.oldattr & backgroundMask) - } - case n == 39: // reset foreground color. - attr &= backgroundMask - attr |= w.oldattr & foregroundMask - case 40 <= n && n <= 47: - attr = (attr & foregroundMask) - if (n-40)&1 != 0 { - attr |= backgroundRed - } - if (n-40)&2 != 0 { - attr |= backgroundGreen - } - if (n-40)&4 != 0 { - attr |= backgroundBlue - } - case n == 48: // set background color. - if i < len(token)-2 && token[i+1] == "5" { - if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256backAttr == nil { - n256setup() - } - attr &= foregroundMask - attr |= n256backAttr[n256] - i += 2 - } - } else { - attr = attr & (w.oldattr & foregroundMask) - } - case n == 49: // reset foreground color. - attr &= foregroundMask - attr |= w.oldattr & backgroundMask - case 90 <= n && n <= 97: - attr = (attr & backgroundMask) - attr |= foregroundIntensity - if (n-90)&1 != 0 { - attr |= foregroundRed - } - if (n-90)&2 != 0 { - attr |= foregroundGreen - } - if (n-90)&4 != 0 { - attr |= foregroundBlue - } - case 100 <= n && n <= 107: - attr = (attr & foregroundMask) - attr |= backgroundIntensity - if (n-100)&1 != 0 { - attr |= backgroundRed - } - if (n-100)&2 != 0 { - attr |= backgroundGreen - } - if (n-100)&4 != 0 { - attr |= backgroundBlue - } - } - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) - } - } - } - } - return len(data) - w.lastbuf.Len(), nil -} - -type consoleColor struct { - rgb int - red bool - green bool - blue bool - intensity bool -} - -func (c consoleColor) foregroundAttr() (attr word) { - if c.red { - attr |= foregroundRed - } - if c.green { - attr |= foregroundGreen - } - if c.blue { - attr |= foregroundBlue - } - if c.intensity { - attr |= foregroundIntensity - } - return -} - -func (c consoleColor) backgroundAttr() (attr word) { - if c.red { - attr |= backgroundRed - } - if c.green { - attr |= backgroundGreen - } - if c.blue { - attr |= backgroundBlue - } - if c.intensity { - attr |= backgroundIntensity - } - return -} - -var color16 = []consoleColor{ - consoleColor{0x000000, false, false, false, false}, - consoleColor{0x000080, false, false, true, false}, - consoleColor{0x008000, false, true, false, false}, - consoleColor{0x008080, false, true, true, false}, - consoleColor{0x800000, true, false, false, false}, - consoleColor{0x800080, true, false, true, false}, - consoleColor{0x808000, true, true, false, false}, - consoleColor{0xc0c0c0, true, true, true, false}, - consoleColor{0x808080, false, false, false, true}, - consoleColor{0x0000ff, false, false, true, true}, - consoleColor{0x00ff00, false, true, false, true}, - consoleColor{0x00ffff, false, true, true, true}, - consoleColor{0xff0000, true, false, false, true}, - consoleColor{0xff00ff, true, false, true, true}, - consoleColor{0xffff00, true, true, false, true}, - consoleColor{0xffffff, true, true, true, true}, -} - -type hsv struct { - h, s, v float32 -} - -func (a hsv) dist(b hsv) float32 { - dh := a.h - b.h - switch { - case dh > 0.5: - dh = 1 - dh - case dh < -0.5: - dh = -1 - dh - } - ds := a.s - b.s - dv := a.v - b.v - return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) -} - -func toHSV(rgb int) hsv { - r, g, b := float32((rgb&0xFF0000)>>16)/256.0, - float32((rgb&0x00FF00)>>8)/256.0, - float32(rgb&0x0000FF)/256.0 - min, max := minmax3f(r, g, b) - h := max - min - if h > 0 { - if max == r { - h = (g - b) / h - if h < 0 { - h += 6 - } - } else if max == g { - h = 2 + (b-r)/h - } else { - h = 4 + (r-g)/h - } - } - h /= 6.0 - s := max - min - if max != 0 { - s /= max - } - v := max - return hsv{h: h, s: s, v: v} -} - -type hsvTable []hsv - -func toHSVTable(rgbTable []consoleColor) hsvTable { - t := make(hsvTable, len(rgbTable)) - for i, c := range rgbTable { - t[i] = toHSV(c.rgb) - } - return t -} - -func (t hsvTable) find(rgb int) consoleColor { - hsv := toHSV(rgb) - n := 7 - l := float32(5.0) - for i, p := range t { - d := hsv.dist(p) - if d < l { - l, n = d, i - } - } - return color16[n] -} - -func minmax3f(a, b, c float32) (min, max float32) { - if a < b { - if b < c { - return a, c - } else if a < c { - return a, b - } else { - return c, b - } - } else { - if a < c { - return b, c - } else if b < c { - return b, a - } else { - return c, a - } - } -} - -var n256foreAttr []word -var n256backAttr []word - -func n256setup() { - n256foreAttr = make([]word, 256) - n256backAttr = make([]word, 256) - t := toHSVTable(color16) - for i, rgb := range color256 { - c := t.find(rgb) - n256foreAttr[i] = c.foregroundAttr() - n256backAttr[i] = c.backgroundAttr() - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go b/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go deleted file mode 100644 index 743555ddea..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go +++ /dev/null @@ -1,230 +0,0 @@ -package formatter - -import ( - "fmt" - "os" - "regexp" - "strconv" - "strings" -) - -// ColorableStdOut and ColorableStdErr enable color output support on Windows -var ColorableStdOut = newColorable(os.Stdout) -var ColorableStdErr = newColorable(os.Stderr) - -const COLS = 80 - -type ColorMode uint8 - -const ( - ColorModeNone ColorMode = iota - ColorModeTerminal - ColorModePassthrough -) - -var SingletonFormatter = New(ColorModeTerminal) - -func F(format string, args ...interface{}) string { - return SingletonFormatter.F(format, args...) -} - -func Fi(indentation uint, format string, args ...interface{}) string { - return SingletonFormatter.Fi(indentation, format, args...) -} - -func Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { - return SingletonFormatter.Fiw(indentation, maxWidth, format, args...) -} - -type Formatter struct { - ColorMode ColorMode - colors map[string]string - styleRe *regexp.Regexp - preserveColorStylingTags bool -} - -func NewWithNoColorBool(noColor bool) Formatter { - if noColor { - return New(ColorModeNone) - } - return New(ColorModeTerminal) -} - -func New(colorMode ColorMode) Formatter { - colorAliases := map[string]int{ - "black": 0, - "red": 1, - "green": 2, - "yellow": 3, - "blue": 4, - "magenta": 5, - "cyan": 6, - "white": 7, - } - for colorAlias, n := range colorAliases { - colorAliases[fmt.Sprintf("bright-%s", colorAlias)] = n + 8 - } - - getColor := func(color, defaultEscapeCode string) string { - color = strings.ToUpper(strings.ReplaceAll(color, "-", "_")) - envVar := fmt.Sprintf("GINKGO_CLI_COLOR_%s", color) - envVarColor := os.Getenv(envVar) - if envVarColor == "" { - return defaultEscapeCode - } - if colorCode, ok := colorAliases[envVarColor]; ok { - return fmt.Sprintf("\x1b[38;5;%dm", colorCode) - } - colorCode, err := strconv.Atoi(envVarColor) - if err != nil || colorCode < 0 || colorCode > 255 { - return defaultEscapeCode - } - return fmt.Sprintf("\x1b[38;5;%dm", colorCode) - } - - f := Formatter{ - ColorMode: colorMode, - colors: map[string]string{ - "/": "\x1b[0m", - "bold": "\x1b[1m", - "underline": "\x1b[4m", - - "red": getColor("red", "\x1b[38;5;9m"), - "orange": getColor("orange", "\x1b[38;5;214m"), - "coral": getColor("coral", "\x1b[38;5;204m"), - "magenta": getColor("magenta", "\x1b[38;5;13m"), - "green": getColor("green", "\x1b[38;5;10m"), - "dark-green": getColor("dark-green", "\x1b[38;5;28m"), - "yellow": getColor("yellow", "\x1b[38;5;11m"), - "light-yellow": getColor("light-yellow", "\x1b[38;5;228m"), - "cyan": getColor("cyan", "\x1b[38;5;14m"), - "gray": getColor("gray", "\x1b[38;5;243m"), - "light-gray": getColor("light-gray", "\x1b[38;5;246m"), - "blue": getColor("blue", "\x1b[38;5;12m"), - }, - } - colors := []string{} - for color := range f.colors { - colors = append(colors, color) - } - f.styleRe = regexp.MustCompile("{{(" + strings.Join(colors, "|") + ")}}") - return f -} - -func (f Formatter) F(format string, args ...interface{}) string { - return f.Fi(0, format, args...) -} - -func (f Formatter) Fi(indentation uint, format string, args ...interface{}) string { - return f.Fiw(indentation, 0, format, args...) -} - -func (f Formatter) Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { - out := f.style(format) - if len(args) > 0 { - out = fmt.Sprintf(out, args...) - } - - if indentation == 0 && maxWidth == 0 { - return out - } - - lines := strings.Split(out, "\n") - - if maxWidth != 0 { - outLines := []string{} - - maxWidth = maxWidth - indentation*2 - for _, line := range lines { - if f.length(line) <= maxWidth { - outLines = append(outLines, line) - continue - } - words := strings.Split(line, " ") - outWords := []string{words[0]} - length := uint(f.length(words[0])) - for _, word := range words[1:] { - wordLength := f.length(word) - if length+wordLength+1 <= maxWidth { - length += wordLength + 1 - outWords = append(outWords, word) - continue - } - outLines = append(outLines, strings.Join(outWords, " ")) - outWords = []string{word} - length = wordLength - } - if len(outWords) > 0 { - outLines = append(outLines, strings.Join(outWords, " ")) - } - } - - lines = outLines - } - - if indentation == 0 { - return strings.Join(lines, "\n") - } - - padding := strings.Repeat(" ", int(indentation)) - for i := range lines { - if lines[i] != "" { - lines[i] = padding + lines[i] - } - } - - return strings.Join(lines, "\n") -} - -func (f Formatter) length(styled string) uint { - n := uint(0) - inStyle := false - for _, b := range styled { - if inStyle { - if b == 'm' { - inStyle = false - } - continue - } - if b == '\x1b' { - inStyle = true - continue - } - n += 1 - } - return n -} - -func (f Formatter) CycleJoin(elements []string, joiner string, cycle []string) string { - if len(elements) == 0 { - return "" - } - n := len(cycle) - out := "" - for i, text := range elements { - out += cycle[i%n] + text - if i < len(elements)-1 { - out += joiner - } - } - out += "{{/}}" - return f.style(out) -} - -func (f Formatter) style(s string) string { - switch f.ColorMode { - case ColorModeNone: - return f.styleRe.ReplaceAllString(s, "") - case ColorModePassthrough: - return s - case ColorModeTerminal: - return f.styleRe.ReplaceAllStringFunc(s, func(match string) string { - if out, ok := f.colors[strings.Trim(match, "{}")]; ok { - return out - } - return match - }) - } - - return "" -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go deleted file mode 100644 index 5db5d1a7bf..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go +++ /dev/null @@ -1,63 +0,0 @@ -package build - -import ( - "fmt" - - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/types" -) - -func BuildBuildCommand() command.Command { - var cliConfig = types.NewDefaultCLIConfig() - var goFlagsConfig = types.NewDefaultGoFlagsConfig() - - flags, err := types.BuildBuildCommandFlagSet(&cliConfig, &goFlagsConfig) - if err != nil { - panic(err) - } - - return command.Command{ - Name: "build", - Flags: flags, - Usage: "ginkgo build ", - ShortDoc: "Build the passed in (or the package in the current directory if left blank).", - DocLink: "precompiling-suites", - Command: func(args []string, _ []string) { - var errors []error - cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) - command.AbortIfErrors("Ginkgo detected configuration issues:", errors) - - buildSpecs(args, cliConfig, goFlagsConfig) - }, - } -} - -func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig) { - suites := internal.FindSuites(args, cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) - if len(suites) == 0 { - command.AbortWith("Found no test suites") - } - - internal.VerifyCLIAndFrameworkVersion(suites) - - opc := internal.NewOrderedParallelCompiler(cliConfig.ComputedNumCompilers()) - opc.StartCompiling(suites, goFlagsConfig) - - for { - suiteIdx, suite := opc.Next() - if suiteIdx >= len(suites) { - break - } - suites[suiteIdx] = suite - if suite.State.Is(internal.TestSuiteStateFailedToCompile) { - fmt.Println(suite.CompilationError.Error()) - } else { - fmt.Printf("Compiled %s.test\n", suite.PackageName) - } - } - - if suites.CountWithState(internal.TestSuiteStateFailedToCompile) > 0 { - command.AbortWith("Failed to compile all tests") - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go deleted file mode 100644 index 2efd286088..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go +++ /dev/null @@ -1,61 +0,0 @@ -package command - -import "fmt" - -type AbortDetails struct { - ExitCode int - Error error - EmitUsage bool -} - -func Abort(details AbortDetails) { - panic(details) -} - -func AbortGracefullyWith(format string, args ...interface{}) { - Abort(AbortDetails{ - ExitCode: 0, - Error: fmt.Errorf(format, args...), - EmitUsage: false, - }) -} - -func AbortWith(format string, args ...interface{}) { - Abort(AbortDetails{ - ExitCode: 1, - Error: fmt.Errorf(format, args...), - EmitUsage: false, - }) -} - -func AbortWithUsage(format string, args ...interface{}) { - Abort(AbortDetails{ - ExitCode: 1, - Error: fmt.Errorf(format, args...), - EmitUsage: true, - }) -} - -func AbortIfError(preamble string, err error) { - if err != nil { - Abort(AbortDetails{ - ExitCode: 1, - Error: fmt.Errorf("%s\n%s", preamble, err.Error()), - EmitUsage: false, - }) - } -} - -func AbortIfErrors(preamble string, errors []error) { - if len(errors) > 0 { - out := "" - for _, err := range errors { - out += err.Error() - } - Abort(AbortDetails{ - ExitCode: 1, - Error: fmt.Errorf("%s\n%s", preamble, out), - EmitUsage: false, - }) - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go deleted file mode 100644 index 12e0e56591..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go +++ /dev/null @@ -1,50 +0,0 @@ -package command - -import ( - "fmt" - "io" - "strings" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/types" -) - -type Command struct { - Name string - Flags types.GinkgoFlagSet - Usage string - ShortDoc string - Documentation string - DocLink string - Command func(args []string, additionalArgs []string) -} - -func (c Command) Run(args []string, additionalArgs []string) { - args, err := c.Flags.Parse(args) - if err != nil { - AbortWithUsage(err.Error()) - } - - c.Command(args, additionalArgs) -} - -func (c Command) EmitUsage(writer io.Writer) { - fmt.Fprintln(writer, formatter.F("{{bold}}"+c.Usage+"{{/}}")) - fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(c.Usage)))) - if c.ShortDoc != "" { - fmt.Fprintln(writer, formatter.Fiw(0, formatter.COLS, c.ShortDoc)) - fmt.Fprintln(writer, "") - } - if c.Documentation != "" { - fmt.Fprintln(writer, formatter.Fiw(0, formatter.COLS, c.Documentation)) - fmt.Fprintln(writer, "") - } - if c.DocLink != "" { - fmt.Fprintln(writer, formatter.Fi(0, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}http://onsi.github.io/ginkgo/#%s{{/}}", c.DocLink)) - fmt.Fprintln(writer, "") - } - flagUsage := c.Flags.Usage() - if flagUsage != "" { - fmt.Fprintf(writer, formatter.F(flagUsage)) - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go deleted file mode 100644 index 88dd8d6b07..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go +++ /dev/null @@ -1,182 +0,0 @@ -package command - -import ( - "fmt" - "io" - "os" - "strings" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/types" -) - -type Program struct { - Name string - Heading string - Commands []Command - DefaultCommand Command - DeprecatedCommands []DeprecatedCommand - - //For testing - leave as nil in production - OutWriter io.Writer - ErrWriter io.Writer - Exiter func(code int) -} - -type DeprecatedCommand struct { - Name string - Deprecation types.Deprecation -} - -func (p Program) RunAndExit(osArgs []string) { - var command Command - deprecationTracker := types.NewDeprecationTracker() - if p.Exiter == nil { - p.Exiter = os.Exit - } - if p.OutWriter == nil { - p.OutWriter = formatter.ColorableStdOut - } - if p.ErrWriter == nil { - p.ErrWriter = formatter.ColorableStdErr - } - - defer func() { - exitCode := 0 - - if r := recover(); r != nil { - details, ok := r.(AbortDetails) - if !ok { - panic(r) - } - - if details.Error != nil { - fmt.Fprintln(p.ErrWriter, formatter.F("{{red}}{{bold}}%s %s{{/}} {{red}}failed{{/}}", p.Name, command.Name)) - fmt.Fprintln(p.ErrWriter, formatter.Fi(1, details.Error.Error())) - } - if details.EmitUsage { - if details.Error != nil { - fmt.Fprintln(p.ErrWriter, "") - } - command.EmitUsage(p.ErrWriter) - } - exitCode = details.ExitCode - } - - command.Flags.ValidateDeprecations(deprecationTracker) - if deprecationTracker.DidTrackDeprecations() { - fmt.Fprintln(p.ErrWriter, deprecationTracker.DeprecationsReport()) - } - p.Exiter(exitCode) - return - }() - - args, additionalArgs := []string{}, []string{} - - foundDelimiter := false - for _, arg := range osArgs[1:] { - if !foundDelimiter { - if arg == "--" { - foundDelimiter = true - continue - } - } - - if foundDelimiter { - additionalArgs = append(additionalArgs, arg) - } else { - args = append(args, arg) - } - } - - command = p.DefaultCommand - if len(args) > 0 { - p.handleHelpRequestsAndExit(p.OutWriter, args) - if command.Name == args[0] { - args = args[1:] - } else { - for _, deprecatedCommand := range p.DeprecatedCommands { - if deprecatedCommand.Name == args[0] { - deprecationTracker.TrackDeprecation(deprecatedCommand.Deprecation) - return - } - } - for _, tryCommand := range p.Commands { - if tryCommand.Name == args[0] { - command, args = tryCommand, args[1:] - break - } - } - } - } - - command.Run(args, additionalArgs) -} - -func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) { - if len(args) == 0 { - return - } - - matchesHelpFlag := func(args ...string) bool { - for _, arg := range args { - if arg == "--help" || arg == "-help" || arg == "-h" || arg == "--h" { - return true - } - } - return false - } - if len(args) == 1 { - if args[0] == "help" || matchesHelpFlag(args[0]) { - p.EmitUsage(writer) - Abort(AbortDetails{}) - } - } else { - var name string - if args[0] == "help" || matchesHelpFlag(args[0]) { - name = args[1] - } else if matchesHelpFlag(args[1:]...) { - name = args[0] - } else { - return - } - - if p.DefaultCommand.Name == name || p.Name == name { - p.DefaultCommand.EmitUsage(writer) - Abort(AbortDetails{}) - } - for _, command := range p.Commands { - if command.Name == name { - command.EmitUsage(writer) - Abort(AbortDetails{}) - } - } - - fmt.Fprintln(writer, formatter.F("{{red}}Unknown Command: {{bold}}%s{{/}}", name)) - fmt.Fprintln(writer, "") - p.EmitUsage(writer) - Abort(AbortDetails{ExitCode: 1}) - } - return -} - -func (p Program) EmitUsage(writer io.Writer) { - fmt.Fprintln(writer, formatter.F(p.Heading)) - fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading)))) - fmt.Fprintln(writer, formatter.F("For usage information for a command, run {{bold}}%s help COMMAND{{/}}.", p.Name)) - fmt.Fprintln(writer, formatter.F("For usage information for the default command, run {{bold}}%s help %s{{/}} or {{bold}}%s help %s{{/}}.", p.Name, p.Name, p.Name, p.DefaultCommand.Name)) - fmt.Fprintln(writer, "") - fmt.Fprintln(writer, formatter.F("The following commands are available:")) - - fmt.Fprintln(writer, formatter.Fi(1, "{{bold}}%s{{/}} or %s {{bold}}%s{{/}} - {{gray}}%s{{/}}", p.Name, p.Name, p.DefaultCommand.Name, p.DefaultCommand.Usage)) - if p.DefaultCommand.ShortDoc != "" { - fmt.Fprintln(writer, formatter.Fi(2, p.DefaultCommand.ShortDoc)) - } - - for _, command := range p.Commands { - fmt.Fprintln(writer, formatter.Fi(1, "{{bold}}%s{{/}} - {{gray}}%s{{/}}", command.Name, command.Usage)) - if command.ShortDoc != "" { - fmt.Fprintln(writer, formatter.Fi(2, command.ShortDoc)) - } - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go deleted file mode 100644 index a367a1fc97..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go +++ /dev/null @@ -1,48 +0,0 @@ -package generators - -var bootstrapText = `package {{.Package}} - -import ( - "testing" - - {{.GinkgoImport}} - {{.GomegaImport}} -) - -func Test{{.FormattedName}}(t *testing.T) { - {{.GomegaPackage}}RegisterFailHandler({{.GinkgoPackage}}Fail) - {{.GinkgoPackage}}RunSpecs(t, "{{.FormattedName}} Suite") -} -` - -var agoutiBootstrapText = `package {{.Package}} - -import ( - "testing" - - {{.GinkgoImport}} - {{.GomegaImport}} - "github.com/sclevine/agouti" -) - -func Test{{.FormattedName}}(t *testing.T) { - {{.GomegaPackage}}RegisterFailHandler({{.GinkgoPackage}}Fail) - {{.GinkgoPackage}}RunSpecs(t, "{{.FormattedName}} Suite") -} - -var agoutiDriver *agouti.WebDriver - -var _ = {{.GinkgoPackage}}BeforeSuite(func() { - // Choose a WebDriver: - - agoutiDriver = agouti.PhantomJS() - // agoutiDriver = agouti.Selenium() - // agoutiDriver = agouti.ChromeDriver() - - {{.GomegaPackage}}Expect(agoutiDriver.Start()).To({{.GomegaPackage}}Succeed()) -}) - -var _ = {{.GinkgoPackage}}AfterSuite(func() { - {{.GomegaPackage}}Expect(agoutiDriver.Stop()).To({{.GomegaPackage}}Succeed()) -}) -` diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go deleted file mode 100644 index 73aff0b7a1..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go +++ /dev/null @@ -1,133 +0,0 @@ -package generators - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "text/template" - - sprig "github.com/go-task/slim-sprig" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/types" -) - -func BuildBootstrapCommand() command.Command { - conf := GeneratorsConfig{} - flags, err := types.NewGinkgoFlagSet( - types.GinkgoFlags{ - {Name: "agouti", KeyPath: "Agouti", - Usage: "If set, bootstrap will generate a bootstrap file for writing Agouti tests"}, - {Name: "nodot", KeyPath: "NoDot", - Usage: "If set, bootstrap will generate a bootstrap test file that does not dot-import ginkgo and gomega"}, - {Name: "internal", KeyPath: "Internal", - Usage: "If set, bootstrap will generate a bootstrap test file that uses the regular package name (i.e. `package X`, not `package X_test`)"}, - {Name: "template", KeyPath: "CustomTemplate", - UsageArgument: "template-file", - Usage: "If specified, generate will use the contents of the file passed as the bootstrap template"}, - {Name: "template-data", KeyPath: "CustomTemplateData", - UsageArgument: "template-data-file", - Usage: "If specified, generate will use the contents of the file passed as data to be rendered in the bootstrap template"}, - }, - &conf, - types.GinkgoFlagSections{}, - ) - - if err != nil { - panic(err) - } - - return command.Command{ - Name: "bootstrap", - Usage: "ginkgo bootstrap", - ShortDoc: "Bootstrap a test suite for the current package", - Documentation: `Tests written in Ginkgo and Gomega require a small amount of boilerplate to hook into Go's testing infrastructure. - -{{bold}}ginkgo bootstrap{{/}} generates this boilerplate for you in a file named X_suite_test.go where X is the name of the package under test.`, - DocLink: "generators", - Flags: flags, - Command: func(_ []string, _ []string) { - generateBootstrap(conf) - }, - } -} - -type bootstrapData struct { - Package string - FormattedName string - - GinkgoImport string - GomegaImport string - GinkgoPackage string - GomegaPackage string - CustomData map[string]any -} - -func generateBootstrap(conf GeneratorsConfig) { - packageName, bootstrapFilePrefix, formattedName := getPackageAndFormattedName() - - data := bootstrapData{ - Package: determinePackageName(packageName, conf.Internal), - FormattedName: formattedName, - - GinkgoImport: `. "github.com/onsi/ginkgo/v2"`, - GomegaImport: `. "github.com/onsi/gomega"`, - GinkgoPackage: "", - GomegaPackage: "", - } - - if conf.NoDot { - data.GinkgoImport = `"github.com/onsi/ginkgo/v2"` - data.GomegaImport = `"github.com/onsi/gomega"` - data.GinkgoPackage = `ginkgo.` - data.GomegaPackage = `gomega.` - } - - targetFile := fmt.Sprintf("%s_suite_test.go", bootstrapFilePrefix) - if internal.FileExists(targetFile) { - command.AbortWith("{{bold}}%s{{/}} already exists", targetFile) - } else { - fmt.Printf("Generating ginkgo test suite bootstrap for %s in:\n\t%s\n", packageName, targetFile) - } - - f, err := os.Create(targetFile) - command.AbortIfError("Failed to create file:", err) - defer f.Close() - - var templateText string - if conf.CustomTemplate != "" { - tpl, err := os.ReadFile(conf.CustomTemplate) - command.AbortIfError("Failed to read custom bootstrap file:", err) - templateText = string(tpl) - if conf.CustomTemplateData != "" { - var tplCustomDataMap map[string]any - tplCustomData, err := os.ReadFile(conf.CustomTemplateData) - command.AbortIfError("Failed to read custom boostrap data file:", err) - if !json.Valid([]byte(tplCustomData)) { - command.AbortWith("Invalid JSON object in custom data file.") - } - //create map from the custom template data - json.Unmarshal(tplCustomData, &tplCustomDataMap) - data.CustomData = tplCustomDataMap - } - } else if conf.Agouti { - templateText = agoutiBootstrapText - } else { - templateText = bootstrapText - } - - //Setting the option to explicitly fail if template is rendered trying to access missing key - bootstrapTemplate, err := template.New("bootstrap").Funcs(sprig.TxtFuncMap()).Option("missingkey=error").Parse(templateText) - command.AbortIfError("Failed to parse bootstrap template:", err) - - buf := &bytes.Buffer{} - //Being explicit about failing sooner during template rendering - //when accessing custom data rather than during the go fmt command - err = bootstrapTemplate.Execute(buf, data) - command.AbortIfError("Failed to render bootstrap template:", err) - - buf.WriteTo(f) - - internal.GoFmt(targetFile) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go deleted file mode 100644 index 48d23f9191..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go +++ /dev/null @@ -1,259 +0,0 @@ -package generators - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - "text/template" - - sprig "github.com/go-task/slim-sprig" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/types" -) - -func BuildGenerateCommand() command.Command { - conf := GeneratorsConfig{} - flags, err := types.NewGinkgoFlagSet( - types.GinkgoFlags{ - {Name: "agouti", KeyPath: "Agouti", - Usage: "If set, generate will create a test file for writing Agouti tests"}, - {Name: "nodot", KeyPath: "NoDot", - Usage: "If set, generate will create a test file that does not dot-import ginkgo and gomega"}, - {Name: "internal", KeyPath: "Internal", - Usage: "If set, generate will create a test file that uses the regular package name (i.e. `package X`, not `package X_test`)"}, - {Name: "template", KeyPath: "CustomTemplate", - UsageArgument: "template-file", - Usage: "If specified, generate will use the contents of the file passed as the test file template"}, - {Name: "template-data", KeyPath: "CustomTemplateData", - UsageArgument: "template-data-file", - Usage: "If specified, generate will use the contents of the file passed as data to be rendered in the test file template"}, - }, - &conf, - types.GinkgoFlagSections{}, - ) - - if err != nil { - panic(err) - } - - return command.Command{ - Name: "generate", - Usage: "ginkgo generate ", - ShortDoc: "Generate a test file named _test.go", - Documentation: `If the optional argument is omitted, a file named after the package in the current directory will be created. - -You can pass multiple to generate multiple files simultaneously. The resulting files are named _test.go. - -You can also pass a of the form "file.go" and generate will emit "file_test.go".`, - DocLink: "generators", - Flags: flags, - Command: func(args []string, _ []string) { - generateTestFiles(conf, args) - }, - } -} - -type specData struct { - Package string - Subject string - PackageImportPath string - ImportPackage bool - - GinkgoImport string - GomegaImport string - GinkgoPackage string - GomegaPackage string - CustomData map[string]any -} - -func generateTestFiles(conf GeneratorsConfig, args []string) { - subjects := args - if len(subjects) == 0 { - subjects = []string{""} - } - for _, subject := range subjects { - generateTestFileForSubject(subject, conf) - } -} - -func generateTestFileForSubject(subject string, conf GeneratorsConfig) { - packageName, specFilePrefix, formattedName := getPackageAndFormattedName() - if subject != "" { - specFilePrefix = formatSubject(subject) - formattedName = prettifyName(specFilePrefix) - } - - if conf.Internal { - specFilePrefix = specFilePrefix + "_internal" - } - - data := specData{ - Package: determinePackageName(packageName, conf.Internal), - Subject: formattedName, - PackageImportPath: getPackageImportPath(), - ImportPackage: !conf.Internal, - - GinkgoImport: `. "github.com/onsi/ginkgo/v2"`, - GomegaImport: `. "github.com/onsi/gomega"`, - GinkgoPackage: "", - GomegaPackage: "", - } - - if conf.NoDot { - data.GinkgoImport = `"github.com/onsi/ginkgo/v2"` - data.GomegaImport = `"github.com/onsi/gomega"` - data.GinkgoPackage = `ginkgo.` - data.GomegaPackage = `gomega.` - } - - targetFile := fmt.Sprintf("%s_test.go", specFilePrefix) - if internal.FileExists(targetFile) { - command.AbortWith("{{bold}}%s{{/}} already exists", targetFile) - } else { - fmt.Printf("Generating ginkgo test for %s in:\n %s\n", data.Subject, targetFile) - } - - f, err := os.Create(targetFile) - command.AbortIfError("Failed to create test file:", err) - defer f.Close() - - var templateText string - if conf.CustomTemplate != "" { - tpl, err := os.ReadFile(conf.CustomTemplate) - command.AbortIfError("Failed to read custom template file:", err) - templateText = string(tpl) - if conf.CustomTemplateData != "" { - var tplCustomDataMap map[string]any - tplCustomData, err := os.ReadFile(conf.CustomTemplateData) - command.AbortIfError("Failed to read custom template data file:", err) - if !json.Valid([]byte(tplCustomData)) { - command.AbortWith("Invalid JSON object in custom data file.") - } - //create map from the custom template data - json.Unmarshal(tplCustomData, &tplCustomDataMap) - data.CustomData = tplCustomDataMap - } - } else if conf.Agouti { - templateText = agoutiSpecText - } else { - templateText = specText - } - - //Setting the option to explicitly fail if template is rendered trying to access missing key - specTemplate, err := template.New("spec").Funcs(sprig.TxtFuncMap()).Option("missingkey=error").Parse(templateText) - command.AbortIfError("Failed to read parse test template:", err) - - //Being explicit about failing sooner during template rendering - //when accessing custom data rather than during the go fmt command - err = specTemplate.Execute(f, data) - command.AbortIfError("Failed to render bootstrap template:", err) - internal.GoFmt(targetFile) -} - -func formatSubject(name string) string { - name = strings.ReplaceAll(name, "-", "_") - name = strings.ReplaceAll(name, " ", "_") - name = strings.Split(name, ".go")[0] - name = strings.Split(name, "_test")[0] - return name -} - -// moduleName returns module name from go.mod from given module root directory -func moduleName(modRoot string) string { - modFile, err := os.Open(filepath.Join(modRoot, "go.mod")) - if err != nil { - return "" - } - - mod := make([]byte, 128) - _, err = modFile.Read(mod) - if err != nil { - return "" - } - - slashSlash := []byte("//") - moduleStr := []byte("module") - - for len(mod) > 0 { - line := mod - mod = nil - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, mod = line[:i], line[i+1:] - } - if i := bytes.Index(line, slashSlash); i >= 0 { - line = line[:i] - } - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, moduleStr) { - continue - } - line = line[len(moduleStr):] - n := len(line) - line = bytes.TrimSpace(line) - if len(line) == n || len(line) == 0 { - continue - } - - if line[0] == '"' || line[0] == '`' { - p, err := strconv.Unquote(string(line)) - if err != nil { - return "" // malformed quoted string or multiline module path - } - return p - } - - return string(line) - } - - return "" // missing module path -} - -func findModuleRoot(dir string) (root string) { - dir = filepath.Clean(dir) - - // Look for enclosing go.mod. - for { - if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { - return dir - } - d := filepath.Dir(dir) - if d == dir { - break - } - dir = d - } - return "" -} - -func getPackageImportPath() string { - workingDir, err := os.Getwd() - if err != nil { - panic(err.Error()) - } - - sep := string(filepath.Separator) - - // Try go.mod file first - modRoot := findModuleRoot(workingDir) - if modRoot != "" { - modName := moduleName(modRoot) - if modName != "" { - cd := strings.ReplaceAll(workingDir, modRoot, "") - cd = strings.ReplaceAll(cd, sep, "/") - return modName + cd - } - } - - // Fallback to GOPATH structure - paths := strings.Split(workingDir, sep+"src"+sep) - if len(paths) == 1 { - fmt.Printf("\nCouldn't identify package import path.\n\n\tginkgo generate\n\nMust be run within a package directory under $GOPATH/src/...\nYou're going to have to change UNKNOWN_PACKAGE_PATH in the generated file...\n\n") - return "UNKNOWN_PACKAGE_PATH" - } - return filepath.ToSlash(paths[len(paths)-1]) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go deleted file mode 100644 index c3470adbfd..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go +++ /dev/null @@ -1,41 +0,0 @@ -package generators - -var specText = `package {{.Package}} - -import ( - {{.GinkgoImport}} - {{.GomegaImport}} - - {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} -) - -var _ = {{.GinkgoPackage}}Describe("{{.Subject}}", func() { - -}) -` - -var agoutiSpecText = `package {{.Package}} - -import ( - {{.GinkgoImport}} - {{.GomegaImport}} - "github.com/sclevine/agouti" - . "github.com/sclevine/agouti/matchers" - - {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} -) - -var _ = {{.GinkgoPackage}}Describe("{{.Subject}}", func() { - var page *agouti.Page - - {{.GinkgoPackage}}BeforeEach(func() { - var err error - page, err = agoutiDriver.NewPage() - {{.GomegaPackage}}Expect(err).NotTo({{.GomegaPackage}}HaveOccurred()) - }) - - {{.GinkgoPackage}}AfterEach(func() { - {{.GomegaPackage}}Expect(page.Destroy()).To({{.GomegaPackage}}Succeed()) - }) -}) -` diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go deleted file mode 100644 index 3046a4487a..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go +++ /dev/null @@ -1,64 +0,0 @@ -package generators - -import ( - "go/build" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/onsi/ginkgo/v2/ginkgo/command" -) - -type GeneratorsConfig struct { - Agouti, NoDot, Internal bool - CustomTemplate string - CustomTemplateData string -} - -func getPackageAndFormattedName() (string, string, string) { - path, err := os.Getwd() - command.AbortIfError("Could not get current working directory:", err) - - dirName := strings.ReplaceAll(filepath.Base(path), "-", "_") - dirName = strings.ReplaceAll(dirName, " ", "_") - - pkg, err := build.ImportDir(path, 0) - packageName := pkg.Name - if err != nil { - packageName = ensureLegalPackageName(dirName) - } - - formattedName := prettifyName(filepath.Base(path)) - return packageName, dirName, formattedName -} - -func ensureLegalPackageName(name string) string { - if name == "_" { - return "underscore" - } - if len(name) == 0 { - return "empty" - } - n, isDigitErr := strconv.Atoi(string(name[0])) - if isDigitErr == nil { - return []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}[n] + name[1:] - } - return name -} - -func prettifyName(name string) string { - name = strings.ReplaceAll(name, "-", " ") - name = strings.ReplaceAll(name, "_", " ") - name = strings.Title(name) - name = strings.ReplaceAll(name, " ", "") - return name -} - -func determinePackageName(name string, internal bool) string { - if internal { - return name - } - - return name + "_test" -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go deleted file mode 100644 index 86da7340d1..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go +++ /dev/null @@ -1,161 +0,0 @@ -package internal - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" - - "github.com/onsi/ginkgo/v2/types" -) - -func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite { - if suite.PathToCompiledTest != "" { - return suite - } - - suite.CompilationError = nil - - path, err := filepath.Abs(filepath.Join(suite.Path, suite.PackageName+".test")) - if err != nil { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to compute compilation target path:\n%s", err.Error()) - return suite - } - - ginkgoInvocationPath, _ := os.Getwd() - ginkgoInvocationPath, _ = filepath.Abs(ginkgoInvocationPath) - packagePath := suite.AbsPath() - pathToInvocationPath, err := filepath.Rel(packagePath, ginkgoInvocationPath) - if err != nil { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to get relative path from package to the current working directory:\n%s", err.Error()) - return suite - } - args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, path, "./", pathToInvocationPath) - if err != nil { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to generate go test compile flags:\n%s", err.Error()) - return suite - } - - cmd := exec.Command("go", args...) - cmd.Dir = suite.Path - output, err := cmd.CombinedOutput() - if err != nil { - if len(output) > 0 { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to compile %s:\n\n%s", suite.PackageName, output) - } else { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to compile %s\n%s", suite.PackageName, err.Error()) - } - return suite - } - - if strings.Contains(string(output), "[no test files]") { - suite.State = TestSuiteStateSkippedDueToEmptyCompilation - return suite - } - - if len(output) > 0 { - fmt.Println(string(output)) - } - - if !FileExists(path) { - suite.State = TestSuiteStateFailedToCompile - suite.CompilationError = fmt.Errorf("Failed to compile %s:\nOutput file %s could not be found", suite.PackageName, path) - return suite - } - - suite.State = TestSuiteStateCompiled - suite.PathToCompiledTest = path - return suite -} - -func Cleanup(goFlagsConfig types.GoFlagsConfig, suites ...TestSuite) { - if goFlagsConfig.BinaryMustBePreserved() { - return - } - for _, suite := range suites { - if !suite.Precompiled { - os.Remove(suite.PathToCompiledTest) - } - } -} - -type parallelSuiteBundle struct { - suite TestSuite - compiled chan TestSuite -} - -type OrderedParallelCompiler struct { - mutex *sync.Mutex - stopped bool - numCompilers int - - idx int - numSuites int - completionChannels []chan TestSuite -} - -func NewOrderedParallelCompiler(numCompilers int) *OrderedParallelCompiler { - return &OrderedParallelCompiler{ - mutex: &sync.Mutex{}, - numCompilers: numCompilers, - } -} - -func (opc *OrderedParallelCompiler) StartCompiling(suites TestSuites, goFlagsConfig types.GoFlagsConfig) { - opc.stopped = false - opc.idx = 0 - opc.numSuites = len(suites) - opc.completionChannels = make([]chan TestSuite, opc.numSuites) - - toCompile := make(chan parallelSuiteBundle, opc.numCompilers) - for compiler := 0; compiler < opc.numCompilers; compiler++ { - go func() { - for bundle := range toCompile { - c, suite := bundle.compiled, bundle.suite - opc.mutex.Lock() - stopped := opc.stopped - opc.mutex.Unlock() - if !stopped { - suite = CompileSuite(suite, goFlagsConfig) - } - c <- suite - } - }() - } - - for idx, suite := range suites { - opc.completionChannels[idx] = make(chan TestSuite, 1) - toCompile <- parallelSuiteBundle{suite, opc.completionChannels[idx]} - if idx == 0 { //compile first suite serially - suite = <-opc.completionChannels[0] - opc.completionChannels[0] <- suite - } - } - - close(toCompile) -} - -func (opc *OrderedParallelCompiler) Next() (int, TestSuite) { - if opc.idx >= opc.numSuites { - return opc.numSuites, TestSuite{} - } - - idx := opc.idx - suite := <-opc.completionChannels[idx] - opc.idx = opc.idx + 1 - - return idx, suite -} - -func (opc *OrderedParallelCompiler) StopAndDrain() { - opc.mutex.Lock() - opc.stopped = true - opc.mutex.Unlock() -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go deleted file mode 100644 index bd3c6d0287..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go +++ /dev/null @@ -1,237 +0,0 @@ -package internal - -import ( - "bytes" - "fmt" - "os" - "os/exec" - "path/filepath" - "regexp" - "strconv" - - "github.com/google/pprof/profile" - "github.com/onsi/ginkgo/v2/reporters" - "github.com/onsi/ginkgo/v2/types" -) - -func AbsPathForGeneratedAsset(assetName string, suite TestSuite, cliConfig types.CLIConfig, process int) string { - suffix := "" - if process != 0 { - suffix = fmt.Sprintf(".%d", process) - } - if cliConfig.OutputDir == "" { - return filepath.Join(suite.AbsPath(), assetName+suffix) - } - outputDir, _ := filepath.Abs(cliConfig.OutputDir) - return filepath.Join(outputDir, suite.NamespacedName()+"_"+assetName+suffix) -} - -func FinalizeProfilesAndReportsForSuites(suites TestSuites, cliConfig types.CLIConfig, suiteConfig types.SuiteConfig, reporterConfig types.ReporterConfig, goFlagsConfig types.GoFlagsConfig) ([]string, error) { - messages := []string{} - suitesWithProfiles := suites.WithState(TestSuiteStatePassed, TestSuiteStateFailed) //anything else won't have actually run and generated a profile - - // merge cover profiles if need be - if goFlagsConfig.Cover && !cliConfig.KeepSeparateCoverprofiles { - coverProfiles := []string{} - for _, suite := range suitesWithProfiles { - if !suite.HasProgrammaticFocus { - coverProfiles = append(coverProfiles, AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0)) - } - } - - if len(coverProfiles) > 0 { - dst := goFlagsConfig.CoverProfile - if cliConfig.OutputDir != "" { - dst = filepath.Join(cliConfig.OutputDir, goFlagsConfig.CoverProfile) - } - err := MergeAndCleanupCoverProfiles(coverProfiles, dst) - if err != nil { - return messages, err - } - coverage, err := GetCoverageFromCoverProfile(dst) - if err != nil { - return messages, err - } - if coverage == 0 { - messages = append(messages, "composite coverage: [no statements]") - } else if suitesWithProfiles.AnyHaveProgrammaticFocus() { - messages = append(messages, fmt.Sprintf("composite coverage: %.1f%% of statements however some suites did not contribute because they included programatically focused specs", coverage)) - } else { - messages = append(messages, fmt.Sprintf("composite coverage: %.1f%% of statements", coverage)) - } - } else { - messages = append(messages, "no composite coverage computed: all suites included programatically focused specs") - } - } - - // copy binaries if need be - for _, suite := range suitesWithProfiles { - if goFlagsConfig.BinaryMustBePreserved() && cliConfig.OutputDir != "" { - src := suite.PathToCompiledTest - dst := filepath.Join(cliConfig.OutputDir, suite.NamespacedName()+".test") - if suite.Precompiled { - if err := CopyFile(src, dst); err != nil { - return messages, err - } - } else { - if err := os.Rename(src, dst); err != nil { - return messages, err - } - } - } - } - - type reportFormat struct { - ReportName string - GenerateFunc func(types.Report, string) error - MergeFunc func([]string, string) ([]string, error) - } - reportFormats := []reportFormat{} - if reporterConfig.JSONReport != "" { - reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.JSONReport, GenerateFunc: reporters.GenerateJSONReport, MergeFunc: reporters.MergeAndCleanupJSONReports}) - } - if reporterConfig.JUnitReport != "" { - reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.JUnitReport, GenerateFunc: reporters.GenerateJUnitReport, MergeFunc: reporters.MergeAndCleanupJUnitReports}) - } - if reporterConfig.TeamcityReport != "" { - reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.TeamcityReport, GenerateFunc: reporters.GenerateTeamcityReport, MergeFunc: reporters.MergeAndCleanupTeamcityReports}) - } - - // Generate reports for suites that failed to run - reportableSuites := suites.ThatAreGinkgoSuites() - for _, suite := range reportableSuites.WithState(TestSuiteStateFailedToCompile, TestSuiteStateFailedDueToTimeout, TestSuiteStateSkippedDueToPriorFailures, TestSuiteStateSkippedDueToEmptyCompilation) { - report := types.Report{ - SuitePath: suite.AbsPath(), - SuiteConfig: suiteConfig, - SuiteSucceeded: false, - } - switch suite.State { - case TestSuiteStateFailedToCompile: - report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, suite.CompilationError.Error()) - case TestSuiteStateFailedDueToTimeout: - report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, TIMEOUT_ELAPSED_FAILURE_REASON) - case TestSuiteStateSkippedDueToPriorFailures: - report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, PRIOR_FAILURES_FAILURE_REASON) - case TestSuiteStateSkippedDueToEmptyCompilation: - report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, EMPTY_SKIP_FAILURE_REASON) - report.SuiteSucceeded = true - } - - for _, format := range reportFormats { - format.GenerateFunc(report, AbsPathForGeneratedAsset(format.ReportName, suite, cliConfig, 0)) - } - } - - // Merge reports unless we've been asked to keep them separate - if !cliConfig.KeepSeparateReports { - for _, format := range reportFormats { - reports := []string{} - for _, suite := range reportableSuites { - reports = append(reports, AbsPathForGeneratedAsset(format.ReportName, suite, cliConfig, 0)) - } - dst := format.ReportName - if cliConfig.OutputDir != "" { - dst = filepath.Join(cliConfig.OutputDir, format.ReportName) - } - mergeMessages, err := format.MergeFunc(reports, dst) - messages = append(messages, mergeMessages...) - if err != nil { - return messages, err - } - } - } - - return messages, nil -} - -//loads each profile, combines them, deletes them, stores them in destination -func MergeAndCleanupCoverProfiles(profiles []string, destination string) error { - combined := &bytes.Buffer{} - modeRegex := regexp.MustCompile(`^mode: .*\n`) - for i, profile := range profiles { - contents, err := os.ReadFile(profile) - if err != nil { - return fmt.Errorf("Unable to read coverage file %s:\n%s", profile, err.Error()) - } - os.Remove(profile) - - // remove the cover mode line from every file - // except the first one - if i > 0 { - contents = modeRegex.ReplaceAll(contents, []byte{}) - } - - _, err = combined.Write(contents) - - // Add a newline to the end of every file if missing. - if err == nil && len(contents) > 0 && contents[len(contents)-1] != '\n' { - _, err = combined.Write([]byte("\n")) - } - - if err != nil { - return fmt.Errorf("Unable to append to coverprofile:\n%s", err.Error()) - } - } - - err := os.WriteFile(destination, combined.Bytes(), 0666) - if err != nil { - return fmt.Errorf("Unable to create combined cover profile:\n%s", err.Error()) - } - return nil -} - -func GetCoverageFromCoverProfile(profile string) (float64, error) { - cmd := exec.Command("go", "tool", "cover", "-func", profile) - output, err := cmd.CombinedOutput() - if err != nil { - return 0, fmt.Errorf("Could not process Coverprofile %s: %s", profile, err.Error()) - } - re := regexp.MustCompile(`total:\s*\(statements\)\s*(\d*\.\d*)\%`) - matches := re.FindStringSubmatch(string(output)) - if matches == nil { - return 0, fmt.Errorf("Could not parse Coverprofile to compute coverage percentage") - } - coverageString := matches[1] - coverage, err := strconv.ParseFloat(coverageString, 64) - if err != nil { - return 0, fmt.Errorf("Could not parse Coverprofile to compute coverage percentage: %s", err.Error()) - } - - return coverage, nil -} - -func MergeProfiles(profilePaths []string, destination string) error { - profiles := []*profile.Profile{} - for _, profilePath := range profilePaths { - proFile, err := os.Open(profilePath) - if err != nil { - return fmt.Errorf("Could not open profile: %s\n%s", profilePath, err.Error()) - } - prof, err := profile.Parse(proFile) - if err != nil { - return fmt.Errorf("Could not parse profile: %s\n%s", profilePath, err.Error()) - } - profiles = append(profiles, prof) - os.Remove(profilePath) - } - - mergedProfile, err := profile.Merge(profiles) - if err != nil { - return fmt.Errorf("Could not merge profiles:\n%s", err.Error()) - } - - outFile, err := os.Create(destination) - if err != nil { - return fmt.Errorf("Could not create merged profile %s:\n%s", destination, err.Error()) - } - err = mergedProfile.Write(outFile) - if err != nil { - return fmt.Errorf("Could not write merged profile %s:\n%s", destination, err.Error()) - } - err = outFile.Close() - if err != nil { - return fmt.Errorf("Could not close merged profile %s:\n%s", destination, err.Error()) - } - - return nil -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go deleted file mode 100644 index 41052ea19d..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go +++ /dev/null @@ -1,355 +0,0 @@ -package internal - -import ( - "bytes" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "regexp" - "strings" - "syscall" - "time" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/internal/parallel_support" - "github.com/onsi/ginkgo/v2/reporters" - "github.com/onsi/ginkgo/v2/types" -) - -func RunCompiledSuite(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { - suite.State = TestSuiteStateFailed - suite.HasProgrammaticFocus = false - - if suite.PathToCompiledTest == "" { - return suite - } - - if suite.IsGinkgo && cliConfig.ComputedProcs() > 1 { - suite = runParallel(suite, ginkgoConfig, reporterConfig, cliConfig, goFlagsConfig, additionalArgs) - } else if suite.IsGinkgo { - suite = runSerial(suite, ginkgoConfig, reporterConfig, cliConfig, goFlagsConfig, additionalArgs) - } else { - suite = runGoTest(suite, cliConfig, goFlagsConfig) - } - runAfterRunHook(cliConfig.AfterRunHook, reporterConfig.NoColor, suite) - return suite -} - -func buildAndStartCommand(suite TestSuite, args []string, pipeToStdout bool) (*exec.Cmd, *bytes.Buffer) { - buf := &bytes.Buffer{} - cmd := exec.Command(suite.PathToCompiledTest, args...) - cmd.Dir = suite.Path - if pipeToStdout { - cmd.Stderr = io.MultiWriter(os.Stdout, buf) - cmd.Stdout = os.Stdout - } else { - cmd.Stderr = buf - cmd.Stdout = buf - } - err := cmd.Start() - command.AbortIfError("Failed to start test suite", err) - - return cmd, buf -} - -func checkForNoTestsWarning(buf *bytes.Buffer) bool { - if strings.Contains(buf.String(), "warning: no tests to run") { - fmt.Fprintf(os.Stderr, `Found no test suites, did you forget to run "ginkgo bootstrap"?`) - return true - } - return false -} - -func runGoTest(suite TestSuite, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig) TestSuite { - // As we run the go test from the suite directory, make sure the cover profile is absolute - // and placed into the expected output directory when one is configured. - if goFlagsConfig.Cover && !filepath.IsAbs(goFlagsConfig.CoverProfile) { - goFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) - } - - args, err := types.GenerateGoTestRunArgs(goFlagsConfig) - command.AbortIfError("Failed to generate test run arguments", err) - cmd, buf := buildAndStartCommand(suite, args, true) - - cmd.Wait() - - exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - passed := (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) - passed = !(checkForNoTestsWarning(buf) && cliConfig.RequireSuite) && passed - if passed { - suite.State = TestSuiteStatePassed - } else { - suite.State = TestSuiteStateFailed - } - - return suite -} - -func runSerial(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { - if goFlagsConfig.Cover { - goFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) - } - if goFlagsConfig.BlockProfile != "" { - goFlagsConfig.BlockProfile = AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, 0) - } - if goFlagsConfig.CPUProfile != "" { - goFlagsConfig.CPUProfile = AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, 0) - } - if goFlagsConfig.MemProfile != "" { - goFlagsConfig.MemProfile = AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, 0) - } - if goFlagsConfig.MutexProfile != "" { - goFlagsConfig.MutexProfile = AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, 0) - } - if reporterConfig.JSONReport != "" { - reporterConfig.JSONReport = AbsPathForGeneratedAsset(reporterConfig.JSONReport, suite, cliConfig, 0) - } - if reporterConfig.JUnitReport != "" { - reporterConfig.JUnitReport = AbsPathForGeneratedAsset(reporterConfig.JUnitReport, suite, cliConfig, 0) - } - if reporterConfig.TeamcityReport != "" { - reporterConfig.TeamcityReport = AbsPathForGeneratedAsset(reporterConfig.TeamcityReport, suite, cliConfig, 0) - } - - args, err := types.GenerateGinkgoTestRunArgs(ginkgoConfig, reporterConfig, goFlagsConfig) - command.AbortIfError("Failed to generate test run arguments", err) - args = append([]string{"--test.timeout=0"}, args...) - args = append(args, additionalArgs...) - - cmd, buf := buildAndStartCommand(suite, args, true) - - cmd.Wait() - - exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - suite.HasProgrammaticFocus = (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) - passed := (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) - passed = !(checkForNoTestsWarning(buf) && cliConfig.RequireSuite) && passed - if passed { - suite.State = TestSuiteStatePassed - } else { - suite.State = TestSuiteStateFailed - } - - if suite.HasProgrammaticFocus { - if goFlagsConfig.Cover { - fmt.Fprintln(os.Stdout, "coverage: no coverfile was generated because specs are programmatically focused") - } - if goFlagsConfig.BlockProfile != "" { - fmt.Fprintln(os.Stdout, "no block profile was generated because specs are programmatically focused") - } - if goFlagsConfig.CPUProfile != "" { - fmt.Fprintln(os.Stdout, "no cpu profile was generated because specs are programmatically focused") - } - if goFlagsConfig.MemProfile != "" { - fmt.Fprintln(os.Stdout, "no mem profile was generated because specs are programmatically focused") - } - if goFlagsConfig.MutexProfile != "" { - fmt.Fprintln(os.Stdout, "no mutex profile was generated because specs are programmatically focused") - } - } - - return suite -} - -func runParallel(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { - type procResult struct { - passed bool - hasProgrammaticFocus bool - } - - numProcs := cliConfig.ComputedProcs() - procOutput := make([]*bytes.Buffer, numProcs) - coverProfiles := []string{} - - blockProfiles := []string{} - cpuProfiles := []string{} - memProfiles := []string{} - mutexProfiles := []string{} - - procResults := make(chan procResult) - - server, err := parallel_support.NewServer(numProcs, reporters.NewDefaultReporter(reporterConfig, formatter.ColorableStdOut)) - command.AbortIfError("Failed to start parallel spec server", err) - server.Start() - defer server.Close() - - if reporterConfig.JSONReport != "" { - reporterConfig.JSONReport = AbsPathForGeneratedAsset(reporterConfig.JSONReport, suite, cliConfig, 0) - } - if reporterConfig.JUnitReport != "" { - reporterConfig.JUnitReport = AbsPathForGeneratedAsset(reporterConfig.JUnitReport, suite, cliConfig, 0) - } - if reporterConfig.TeamcityReport != "" { - reporterConfig.TeamcityReport = AbsPathForGeneratedAsset(reporterConfig.TeamcityReport, suite, cliConfig, 0) - } - - for proc := 1; proc <= numProcs; proc++ { - procGinkgoConfig := ginkgoConfig - procGinkgoConfig.ParallelProcess, procGinkgoConfig.ParallelTotal, procGinkgoConfig.ParallelHost = proc, numProcs, server.Address() - - procGoFlagsConfig := goFlagsConfig - if goFlagsConfig.Cover { - procGoFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, proc) - coverProfiles = append(coverProfiles, procGoFlagsConfig.CoverProfile) - } - if goFlagsConfig.BlockProfile != "" { - procGoFlagsConfig.BlockProfile = AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, proc) - blockProfiles = append(blockProfiles, procGoFlagsConfig.BlockProfile) - } - if goFlagsConfig.CPUProfile != "" { - procGoFlagsConfig.CPUProfile = AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, proc) - cpuProfiles = append(cpuProfiles, procGoFlagsConfig.CPUProfile) - } - if goFlagsConfig.MemProfile != "" { - procGoFlagsConfig.MemProfile = AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, proc) - memProfiles = append(memProfiles, procGoFlagsConfig.MemProfile) - } - if goFlagsConfig.MutexProfile != "" { - procGoFlagsConfig.MutexProfile = AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, proc) - mutexProfiles = append(mutexProfiles, procGoFlagsConfig.MutexProfile) - } - - args, err := types.GenerateGinkgoTestRunArgs(procGinkgoConfig, reporterConfig, procGoFlagsConfig) - command.AbortIfError("Failed to generate test run arguments", err) - args = append([]string{"--test.timeout=0"}, args...) - args = append(args, additionalArgs...) - - cmd, buf := buildAndStartCommand(suite, args, false) - procOutput[proc-1] = buf - server.RegisterAlive(proc, func() bool { return cmd.ProcessState == nil || !cmd.ProcessState.Exited() }) - - go func() { - cmd.Wait() - exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - procResults <- procResult{ - passed: (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE), - hasProgrammaticFocus: exitStatus == types.GINKGO_FOCUS_EXIT_CODE, - } - }() - } - - passed := true - for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { - result := <-procResults - passed = passed && result.passed - suite.HasProgrammaticFocus = suite.HasProgrammaticFocus || result.hasProgrammaticFocus - } - if passed { - suite.State = TestSuiteStatePassed - } else { - suite.State = TestSuiteStateFailed - } - - select { - case <-server.GetSuiteDone(): - fmt.Println("") - case <-time.After(time.Second): - //one of the nodes never finished reporting to the server. Something must have gone wrong. - fmt.Fprint(formatter.ColorableStdErr, formatter.F("\n{{bold}}{{red}}Ginkgo timed out waiting for all parallel procs to report back{{/}}\n")) - fmt.Fprint(formatter.ColorableStdErr, formatter.F("{{gray}}Test suite:{{/}} %s (%s)\n\n", suite.PackageName, suite.Path)) - fmt.Fprint(formatter.ColorableStdErr, formatter.Fiw(0, formatter.COLS, "This occurs if a parallel process exits before it reports its results to the Ginkgo CLI. The CLI will now print out all the stdout/stderr output it's collected from the running processes. However you may not see anything useful in these logs because the individual test processes usually intercept output to stdout/stderr in order to capture it in the spec reports.\n\nYou may want to try rerunning your test suite with {{light-gray}}--output-interceptor-mode=none{{/}} to see additional output here and debug your suite.\n")) - fmt.Fprintln(formatter.ColorableStdErr, " ") - for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { - fmt.Fprintf(formatter.ColorableStdErr, formatter.F("{{bold}}Output from proc %d:{{/}}\n", proc)) - fmt.Fprintln(os.Stderr, formatter.Fi(1, "%s", procOutput[proc-1].String())) - } - fmt.Fprintf(os.Stderr, "** End **") - } - - for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { - output := procOutput[proc-1].String() - if proc == 1 && checkForNoTestsWarning(procOutput[0]) && cliConfig.RequireSuite { - suite.State = TestSuiteStateFailed - } - if strings.Contains(output, "deprecated Ginkgo functionality") { - fmt.Fprintln(os.Stderr, output) - } - } - - if len(coverProfiles) > 0 { - if suite.HasProgrammaticFocus { - fmt.Fprintln(os.Stdout, "coverage: no coverfile was generated because specs are programmatically focused") - } else { - coverProfile := AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) - err := MergeAndCleanupCoverProfiles(coverProfiles, coverProfile) - command.AbortIfError("Failed to combine cover profiles", err) - - coverage, err := GetCoverageFromCoverProfile(coverProfile) - command.AbortIfError("Failed to compute coverage", err) - if coverage == 0 { - fmt.Fprintln(os.Stdout, "coverage: [no statements]") - } else { - fmt.Fprintf(os.Stdout, "coverage: %.1f%% of statements\n", coverage) - } - } - } - if len(blockProfiles) > 0 { - if suite.HasProgrammaticFocus { - fmt.Fprintln(os.Stdout, "no block profile was generated because specs are programmatically focused") - } else { - blockProfile := AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, 0) - err := MergeProfiles(blockProfiles, blockProfile) - command.AbortIfError("Failed to combine blockprofiles", err) - } - } - if len(cpuProfiles) > 0 { - if suite.HasProgrammaticFocus { - fmt.Fprintln(os.Stdout, "no cpu profile was generated because specs are programmatically focused") - } else { - cpuProfile := AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, 0) - err := MergeProfiles(cpuProfiles, cpuProfile) - command.AbortIfError("Failed to combine cpuprofiles", err) - } - } - if len(memProfiles) > 0 { - if suite.HasProgrammaticFocus { - fmt.Fprintln(os.Stdout, "no mem profile was generated because specs are programmatically focused") - } else { - memProfile := AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, 0) - err := MergeProfiles(memProfiles, memProfile) - command.AbortIfError("Failed to combine memprofiles", err) - } - } - if len(mutexProfiles) > 0 { - if suite.HasProgrammaticFocus { - fmt.Fprintln(os.Stdout, "no mutex profile was generated because specs are programmatically focused") - } else { - mutexProfile := AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, 0) - err := MergeProfiles(mutexProfiles, mutexProfile) - command.AbortIfError("Failed to combine mutexprofiles", err) - } - } - - return suite -} - -func runAfterRunHook(command string, noColor bool, suite TestSuite) { - if command == "" { - return - } - f := formatter.NewWithNoColorBool(noColor) - - // Allow for string replacement to pass input to the command - passed := "[FAIL]" - if suite.State.Is(TestSuiteStatePassed) { - passed = "[PASS]" - } - command = strings.ReplaceAll(command, "(ginkgo-suite-passed)", passed) - command = strings.ReplaceAll(command, "(ginkgo-suite-name)", suite.PackageName) - - // Must break command into parts - splitArgs := regexp.MustCompile(`'.+'|".+"|\S+`) - parts := splitArgs.FindAllString(command, -1) - - output, err := exec.Command(parts[0], parts[1:]...).CombinedOutput() - if err != nil { - fmt.Fprintln(formatter.ColorableStdOut, f.Fi(0, "{{red}}{{bold}}After-run-hook failed:{{/}}")) - fmt.Fprintln(formatter.ColorableStdOut, f.Fi(1, "{{red}}%s{{/}}", output)) - } else { - fmt.Fprintln(formatter.ColorableStdOut, f.Fi(0, "{{green}}{{bold}}After-run-hook succeeded:{{/}}")) - fmt.Fprintln(formatter.ColorableStdOut, f.Fi(1, "{{green}}%s{{/}}", output)) - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go deleted file mode 100644 index 64dcb1b78c..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go +++ /dev/null @@ -1,283 +0,0 @@ -package internal - -import ( - "errors" - "math/rand" - "os" - "path" - "path/filepath" - "regexp" - "strings" - - "github.com/onsi/ginkgo/v2/types" -) - -const TIMEOUT_ELAPSED_FAILURE_REASON = "Suite did not run because the timeout elapsed" -const PRIOR_FAILURES_FAILURE_REASON = "Suite did not run because prior suites failed and --keep-going is not set" -const EMPTY_SKIP_FAILURE_REASON = "Suite did not run go test reported that no test files were found" - -type TestSuiteState uint - -const ( - TestSuiteStateInvalid TestSuiteState = iota - - TestSuiteStateUncompiled - TestSuiteStateCompiled - - TestSuiteStatePassed - - TestSuiteStateSkippedDueToEmptyCompilation - TestSuiteStateSkippedByFilter - TestSuiteStateSkippedDueToPriorFailures - - TestSuiteStateFailed - TestSuiteStateFailedDueToTimeout - TestSuiteStateFailedToCompile -) - -var TestSuiteStateFailureStates = []TestSuiteState{TestSuiteStateFailed, TestSuiteStateFailedDueToTimeout, TestSuiteStateFailedToCompile} - -func (state TestSuiteState) Is(states ...TestSuiteState) bool { - for _, suiteState := range states { - if suiteState == state { - return true - } - } - - return false -} - -type TestSuite struct { - Path string - PackageName string - IsGinkgo bool - - Precompiled bool - PathToCompiledTest string - CompilationError error - - HasProgrammaticFocus bool - State TestSuiteState -} - -func (ts TestSuite) AbsPath() string { - path, _ := filepath.Abs(ts.Path) - return path -} - -func (ts TestSuite) NamespacedName() string { - name := relPath(ts.Path) - name = strings.TrimLeft(name, "."+string(filepath.Separator)) - name = strings.ReplaceAll(name, string(filepath.Separator), "_") - name = strings.ReplaceAll(name, " ", "_") - if name == "" { - return ts.PackageName - } - return name -} - -type TestSuites []TestSuite - -func (ts TestSuites) AnyHaveProgrammaticFocus() bool { - for _, suite := range ts { - if suite.HasProgrammaticFocus { - return true - } - } - - return false -} - -func (ts TestSuites) ThatAreGinkgoSuites() TestSuites { - out := TestSuites{} - for _, suite := range ts { - if suite.IsGinkgo { - out = append(out, suite) - } - } - return out -} - -func (ts TestSuites) CountWithState(states ...TestSuiteState) int { - n := 0 - for _, suite := range ts { - if suite.State.Is(states...) { - n += 1 - } - } - - return n -} - -func (ts TestSuites) WithState(states ...TestSuiteState) TestSuites { - out := TestSuites{} - for _, suite := range ts { - if suite.State.Is(states...) { - out = append(out, suite) - } - } - - return out -} - -func (ts TestSuites) WithoutState(states ...TestSuiteState) TestSuites { - out := TestSuites{} - for _, suite := range ts { - if !suite.State.Is(states...) { - out = append(out, suite) - } - } - - return out -} - -func (ts TestSuites) ShuffledCopy(seed int64) TestSuites { - out := make(TestSuites, len(ts)) - permutation := rand.New(rand.NewSource(seed)).Perm(len(ts)) - for i, j := range permutation { - out[i] = ts[j] - } - return out -} - -func FindSuites(args []string, cliConfig types.CLIConfig, allowPrecompiled bool) TestSuites { - suites := TestSuites{} - - if len(args) > 0 { - for _, arg := range args { - if allowPrecompiled { - suite, err := precompiledTestSuite(arg) - if err == nil { - suites = append(suites, suite) - continue - } - } - recurseForSuite := cliConfig.Recurse - if strings.HasSuffix(arg, "/...") && arg != "/..." { - arg = arg[:len(arg)-4] - recurseForSuite = true - } - suites = append(suites, suitesInDir(arg, recurseForSuite)...) - } - } else { - suites = suitesInDir(".", cliConfig.Recurse) - } - - if cliConfig.SkipPackage != "" { - skipFilters := strings.Split(cliConfig.SkipPackage, ",") - for idx := range suites { - for _, skipFilter := range skipFilters { - if strings.Contains(suites[idx].Path, skipFilter) { - suites[idx].State = TestSuiteStateSkippedByFilter - break - } - } - } - } - - return suites -} - -func precompiledTestSuite(path string) (TestSuite, error) { - info, err := os.Stat(path) - if err != nil { - return TestSuite{}, err - } - - if info.IsDir() { - return TestSuite{}, errors.New("this is a directory, not a file") - } - - if filepath.Ext(path) != ".test" && filepath.Ext(path) != ".exe" { - return TestSuite{}, errors.New("this is not a .test binary") - } - - if filepath.Ext(path) == ".test" && info.Mode()&0111 == 0 { - return TestSuite{}, errors.New("this is not executable") - } - - dir := relPath(filepath.Dir(path)) - packageName := strings.TrimSuffix(filepath.Base(path), ".exe") - packageName = strings.TrimSuffix(packageName, ".test") - - path, err = filepath.Abs(path) - if err != nil { - return TestSuite{}, err - } - - return TestSuite{ - Path: dir, - PackageName: packageName, - IsGinkgo: true, - Precompiled: true, - PathToCompiledTest: path, - State: TestSuiteStateCompiled, - }, nil -} - -func suitesInDir(dir string, recurse bool) TestSuites { - suites := TestSuites{} - - if path.Base(dir) == "vendor" { - return suites - } - - files, _ := os.ReadDir(dir) - re := regexp.MustCompile(`^[^._].*_test\.go$`) - for _, file := range files { - if !file.IsDir() && re.Match([]byte(file.Name())) { - suite := TestSuite{ - Path: relPath(dir), - PackageName: packageNameForSuite(dir), - IsGinkgo: filesHaveGinkgoSuite(dir, files), - State: TestSuiteStateUncompiled, - } - suites = append(suites, suite) - break - } - } - - if recurse { - re = regexp.MustCompile(`^[._]`) - for _, file := range files { - if file.IsDir() && !re.Match([]byte(file.Name())) { - suites = append(suites, suitesInDir(dir+"/"+file.Name(), recurse)...) - } - } - } - - return suites -} - -func relPath(dir string) string { - dir, _ = filepath.Abs(dir) - cwd, _ := os.Getwd() - dir, _ = filepath.Rel(cwd, filepath.Clean(dir)) - - if string(dir[0]) != "." { - dir = "." + string(filepath.Separator) + dir - } - - return dir -} - -func packageNameForSuite(dir string) string { - path, _ := filepath.Abs(dir) - return filepath.Base(path) -} - -func filesHaveGinkgoSuite(dir string, files []os.DirEntry) bool { - reTestFile := regexp.MustCompile(`_test\.go$`) - reGinkgo := regexp.MustCompile(`package ginkgo|\/ginkgo"|\/ginkgo\/v2"|\/ginkgo\/v2/dsl/`) - - for _, file := range files { - if !file.IsDir() && reTestFile.Match([]byte(file.Name())) { - contents, _ := os.ReadFile(dir + "/" + file.Name()) - if reGinkgo.Match(contents) { - return true - } - } - } - - return false -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go deleted file mode 100644 index bd9ca7d51e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go +++ /dev/null @@ -1,86 +0,0 @@ -package internal - -import ( - "fmt" - "io" - "os" - "os/exec" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/ginkgo/command" -) - -func FileExists(path string) bool { - _, err := os.Stat(path) - return err == nil -} - -func CopyFile(src string, dest string) error { - srcFile, err := os.Open(src) - if err != nil { - return err - } - - srcStat, err := srcFile.Stat() - if err != nil { - return err - } - - if _, err := os.Stat(dest); err == nil { - os.Remove(dest) - } - - destFile, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, srcStat.Mode()) - if err != nil { - return err - } - - _, err = io.Copy(destFile, srcFile) - if err != nil { - return err - } - - if err := srcFile.Close(); err != nil { - return err - } - return destFile.Close() -} - -func GoFmt(path string) { - out, err := exec.Command("go", "fmt", path).CombinedOutput() - if err != nil { - command.AbortIfError(fmt.Sprintf("Could not fmt:\n%s\n", string(out)), err) - } -} - -func PluralizedWord(singular, plural string, count int) string { - if count == 1 { - return singular - } - return plural -} - -func FailedSuitesReport(suites TestSuites, f formatter.Formatter) string { - out := "" - out += "There were failures detected in the following suites:\n" - - maxPackageNameLength := 0 - for _, suite := range suites.WithState(TestSuiteStateFailureStates...) { - if len(suite.PackageName) > maxPackageNameLength { - maxPackageNameLength = len(suite.PackageName) - } - } - - packageNameFormatter := fmt.Sprintf("%%%ds", maxPackageNameLength) - for _, suite := range suites { - switch suite.State { - case TestSuiteStateFailed: - out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s{{/}}\n", suite.PackageName, suite.Path) - case TestSuiteStateFailedToCompile: - out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s {{magenta}}[Compilation failure]{{/}}\n", suite.PackageName, suite.Path) - case TestSuiteStateFailedDueToTimeout: - out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s {{orange}}[%s]{{/}}\n", suite.PackageName, suite.Path, TIMEOUT_ELAPSED_FAILURE_REASON) - } - } - return out -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go deleted file mode 100644 index 9da1bab3db..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go +++ /dev/null @@ -1,54 +0,0 @@ -package internal - -import ( - "fmt" - "os/exec" - "regexp" - "strings" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/types" -) - -var versiorRe = regexp.MustCompile(`v(\d+\.\d+\.\d+)`) - -func VerifyCLIAndFrameworkVersion(suites TestSuites) { - cliVersion := types.VERSION - mismatches := map[string][]string{} - - for _, suite := range suites { - cmd := exec.Command("go", "list", "-m", "github.com/onsi/ginkgo/v2") - cmd.Dir = suite.Path - output, err := cmd.CombinedOutput() - if err != nil { - continue - } - components := strings.Split(string(output), " ") - if len(components) != 2 { - continue - } - matches := versiorRe.FindStringSubmatch(components[1]) - if matches == nil || len(matches) != 2 { - continue - } - libraryVersion := matches[1] - if cliVersion != libraryVersion { - mismatches[libraryVersion] = append(mismatches[libraryVersion], suite.PackageName) - } - } - - if len(mismatches) == 0 { - return - } - - fmt.Println(formatter.F("{{red}}{{bold}}Ginkgo detected a version mismatch between the Ginkgo CLI and the version of Ginkgo imported by your packages:{{/}}")) - - fmt.Println(formatter.Fi(1, "Ginkgo CLI Version:")) - fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}}", cliVersion)) - fmt.Println(formatter.Fi(1, "Mismatched package versions found:")) - for version, packages := range mismatches { - fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}} used by %s", version, strings.Join(packages, ", "))) - } - fmt.Println("") - fmt.Println(formatter.Fiw(1, formatter.COLS, "{{gray}}Ginkgo will continue to attempt to run but you may see errors (including flag parsing errors) and should either update your go.mod or your version of the Ginkgo CLI to match.\n\nTo install the matching version of the CLI run\n {{bold}}go install github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file. Alternatively you can use\n {{bold}}go run github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file to invoke the matching version of the Ginkgo CLI.\n\nIf you are attempting to test multiple packages that each have a different version of the Ginkgo library with a single Ginkgo CLI that is currently unsupported.\n{{/}}")) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go deleted file mode 100644 index 6c61f09d1b..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go +++ /dev/null @@ -1,123 +0,0 @@ -package labels - -import ( - "fmt" - "go/ast" - "go/parser" - "go/token" - "sort" - "strconv" - "strings" - - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/types" - "golang.org/x/tools/go/ast/inspector" -) - -func BuildLabelsCommand() command.Command { - var cliConfig = types.NewDefaultCLIConfig() - - flags, err := types.BuildLabelsCommandFlagSet(&cliConfig) - if err != nil { - panic(err) - } - - return command.Command{ - Name: "labels", - Usage: "ginkgo labels ", - Flags: flags, - ShortDoc: "List labels detected in the passed-in packages (or the package in the current directory if left blank).", - DocLink: "spec-labels", - Command: func(args []string, _ []string) { - ListLabels(args, cliConfig) - }, - } -} - -func ListLabels(args []string, cliConfig types.CLIConfig) { - suites := internal.FindSuites(args, cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) - if len(suites) == 0 { - command.AbortWith("Found no test suites") - } - for _, suite := range suites { - labels := fetchLabelsFromPackage(suite.Path) - if len(labels) == 0 { - fmt.Printf("%s: No labels found\n", suite.PackageName) - } else { - fmt.Printf("%s: [%s]\n", suite.PackageName, strings.Join(labels, ", ")) - } - } -} - -func fetchLabelsFromPackage(packagePath string) []string { - fset := token.NewFileSet() - parsedPackages, err := parser.ParseDir(fset, packagePath, nil, 0) - command.AbortIfError("Failed to parse package source:", err) - - files := []*ast.File{} - hasTestPackage := false - for key, pkg := range parsedPackages { - if strings.HasSuffix(key, "_test") { - hasTestPackage = true - for _, file := range pkg.Files { - files = append(files, file) - } - } - } - if !hasTestPackage { - for _, pkg := range parsedPackages { - for _, file := range pkg.Files { - files = append(files, file) - } - } - } - - seen := map[string]bool{} - labels := []string{} - ispr := inspector.New(files) - ispr.Preorder([]ast.Node{&ast.CallExpr{}}, func(n ast.Node) { - potentialLabels := fetchLabels(n.(*ast.CallExpr)) - for _, label := range potentialLabels { - if !seen[label] { - seen[label] = true - labels = append(labels, strconv.Quote(label)) - } - } - }) - - sort.Strings(labels) - return labels -} - -func fetchLabels(callExpr *ast.CallExpr) []string { - out := []string{} - switch expr := callExpr.Fun.(type) { - case *ast.Ident: - if expr.Name != "Label" { - return out - } - case *ast.SelectorExpr: - if expr.Sel.Name != "Label" { - return out - } - default: - return out - } - for _, arg := range callExpr.Args { - switch expr := arg.(type) { - case *ast.BasicLit: - if expr.Kind == token.STRING { - unquoted, err := strconv.Unquote(expr.Value) - if err != nil { - unquoted = expr.Value - } - validated, err := types.ValidateAndCleanupLabel(unquoted, types.CodeLocation{}) - if err == nil { - out = append(out, validated) - } - } - } - } - return out -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go deleted file mode 100644 index e9abb27d8b..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/onsi/ginkgo/v2/ginkgo/build" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/generators" - "github.com/onsi/ginkgo/v2/ginkgo/labels" - "github.com/onsi/ginkgo/v2/ginkgo/outline" - "github.com/onsi/ginkgo/v2/ginkgo/run" - "github.com/onsi/ginkgo/v2/ginkgo/unfocus" - "github.com/onsi/ginkgo/v2/ginkgo/watch" - "github.com/onsi/ginkgo/v2/types" -) - -var program command.Program - -func GenerateCommands() []command.Command { - return []command.Command{ - watch.BuildWatchCommand(), - build.BuildBuildCommand(), - generators.BuildBootstrapCommand(), - generators.BuildGenerateCommand(), - labels.BuildLabelsCommand(), - outline.BuildOutlineCommand(), - unfocus.BuildUnfocusCommand(), - BuildVersionCommand(), - } -} - -func main() { - program = command.Program{ - Name: "ginkgo", - Heading: fmt.Sprintf("Ginkgo Version %s", types.VERSION), - Commands: GenerateCommands(), - DefaultCommand: run.BuildRunCommand(), - DeprecatedCommands: []command.DeprecatedCommand{ - {Name: "convert", Deprecation: types.Deprecations.Convert()}, - {Name: "blur", Deprecation: types.Deprecations.Blur()}, - {Name: "nodot", Deprecation: types.Deprecations.Nodot()}, - }, - } - - program.RunAndExit(os.Args) -} - -func BuildVersionCommand() command.Command { - return command.Command{ - Name: "version", - Usage: "ginkgo version", - ShortDoc: "Print Ginkgo's version", - Command: func(_ []string, _ []string) { - fmt.Printf("Ginkgo Version %s\n", types.VERSION) - }, - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go deleted file mode 100644 index 0b9b19fe74..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go +++ /dev/null @@ -1,302 +0,0 @@ -package outline - -import ( - "github.com/onsi/ginkgo/v2/types" - "go/ast" - "go/token" - "strconv" -) - -const ( - // undefinedTextAlt is used if the spec/container text cannot be derived - undefinedTextAlt = "undefined" -) - -// ginkgoMetadata holds useful bits of information for every entry in the outline -type ginkgoMetadata struct { - // Name is the spec or container function name, e.g. `Describe` or `It` - Name string `json:"name"` - - // Text is the `text` argument passed to specs, and some containers - Text string `json:"text"` - - // Start is the position of first character of the spec or container block - Start int `json:"start"` - - // End is the position of first character immediately after the spec or container block - End int `json:"end"` - - Spec bool `json:"spec"` - Focused bool `json:"focused"` - Pending bool `json:"pending"` - Labels []string `json:"labels"` -} - -// ginkgoNode is used to construct the outline as a tree -type ginkgoNode struct { - ginkgoMetadata - Nodes []*ginkgoNode `json:"nodes"` -} - -type walkFunc func(n *ginkgoNode) - -func (n *ginkgoNode) PreOrder(f walkFunc) { - f(n) - for _, m := range n.Nodes { - m.PreOrder(f) - } -} - -func (n *ginkgoNode) PostOrder(f walkFunc) { - for _, m := range n.Nodes { - m.PostOrder(f) - } - f(n) -} - -func (n *ginkgoNode) Walk(pre, post walkFunc) { - pre(n) - for _, m := range n.Nodes { - m.Walk(pre, post) - } - post(n) -} - -// PropagateInheritedProperties propagates the Pending and Focused properties -// through the subtree rooted at n. -func (n *ginkgoNode) PropagateInheritedProperties() { - n.PreOrder(func(thisNode *ginkgoNode) { - for _, descendantNode := range thisNode.Nodes { - if thisNode.Pending { - descendantNode.Pending = true - descendantNode.Focused = false - } - if thisNode.Focused && !descendantNode.Pending { - descendantNode.Focused = true - } - } - }) -} - -// BackpropagateUnfocus propagates the Focused property through the subtree -// rooted at n. It applies the rule described in the Ginkgo docs: -// > Nested programmatically focused specs follow a simple rule: if a -// > leaf-node is marked focused, any of its ancestor nodes that are marked -// > focus will be unfocused. -func (n *ginkgoNode) BackpropagateUnfocus() { - focusedSpecInSubtreeStack := []bool{} - n.PostOrder(func(thisNode *ginkgoNode) { - if thisNode.Spec { - focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, thisNode.Focused) - return - } - focusedSpecInSubtree := false - for range thisNode.Nodes { - focusedSpecInSubtree = focusedSpecInSubtree || focusedSpecInSubtreeStack[len(focusedSpecInSubtreeStack)-1] - focusedSpecInSubtreeStack = focusedSpecInSubtreeStack[0 : len(focusedSpecInSubtreeStack)-1] - } - focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, focusedSpecInSubtree) - if focusedSpecInSubtree { - thisNode.Focused = false - } - }) - -} - -func packageAndIdentNamesFromCallExpr(ce *ast.CallExpr) (string, string, bool) { - switch ex := ce.Fun.(type) { - case *ast.Ident: - return "", ex.Name, true - case *ast.SelectorExpr: - pkgID, ok := ex.X.(*ast.Ident) - if !ok { - return "", "", false - } - // A package identifier is top-level, so Obj must be nil - if pkgID.Obj != nil { - return "", "", false - } - if ex.Sel == nil { - return "", "", false - } - return pkgID.Name, ex.Sel.Name, true - default: - return "", "", false - } -} - -// absoluteOffsetsForNode derives the absolute character offsets of the node start and -// end positions. -func absoluteOffsetsForNode(fset *token.FileSet, n ast.Node) (start, end int) { - return fset.PositionFor(n.Pos(), false).Offset, fset.PositionFor(n.End(), false).Offset -} - -// ginkgoNodeFromCallExpr derives an outline entry from a go AST subtree -// corresponding to a Ginkgo container or spec. -func ginkgoNodeFromCallExpr(fset *token.FileSet, ce *ast.CallExpr, ginkgoPackageName *string) (*ginkgoNode, bool) { - packageName, identName, ok := packageAndIdentNamesFromCallExpr(ce) - if !ok { - return nil, false - } - - n := ginkgoNode{} - n.Name = identName - n.Start, n.End = absoluteOffsetsForNode(fset, ce) - n.Nodes = make([]*ginkgoNode, 0) - switch identName { - case "It", "Specify", "Entry": - n.Spec = true - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - n.Pending = pendingFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "FIt", "FSpecify", "FEntry": - n.Spec = true - n.Focused = true - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "PIt", "PSpecify", "XIt", "XSpecify", "PEntry", "XEntry": - n.Spec = true - n.Pending = true - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "Context", "Describe", "When", "DescribeTable": - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - n.Pending = pendingFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "FContext", "FDescribe", "FWhen", "FDescribeTable": - n.Focused = true - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "PContext", "PDescribe", "PWhen", "XContext", "XDescribe", "XWhen", "PDescribeTable", "XDescribeTable": - n.Pending = true - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - n.Labels = labelFromCallExpr(ce) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "By": - n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "AfterEach", "BeforeEach": - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "JustAfterEach", "JustBeforeEach": - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "AfterSuite", "BeforeSuite": - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - case "SynchronizedAfterSuite", "SynchronizedBeforeSuite": - return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName - default: - return nil, false - } -} - -// textOrAltFromCallExpr tries to derive the "text" of a Ginkgo spec or -// container. If it cannot derive it, it returns the alt text. -func textOrAltFromCallExpr(ce *ast.CallExpr, alt string) string { - text, defined := textFromCallExpr(ce) - if !defined { - return alt - } - return text -} - -// textFromCallExpr tries to derive the "text" of a Ginkgo spec or container. If -// it cannot derive it, it returns false. -func textFromCallExpr(ce *ast.CallExpr) (string, bool) { - if len(ce.Args) < 1 { - return "", false - } - text, ok := ce.Args[0].(*ast.BasicLit) - if !ok { - return "", false - } - switch text.Kind { - case token.CHAR, token.STRING: - // For token.CHAR and token.STRING, Value is quoted - unquoted, err := strconv.Unquote(text.Value) - if err != nil { - // If unquoting fails, just use the raw Value - return text.Value, true - } - return unquoted, true - default: - return text.Value, true - } -} - -func labelFromCallExpr(ce *ast.CallExpr) []string { - - labels := []string{} - if len(ce.Args) < 2 { - return labels - } - - for _, arg := range ce.Args[1:] { - switch expr := arg.(type) { - case *ast.CallExpr: - id, ok := expr.Fun.(*ast.Ident) - if !ok { - // to skip over cases where the expr.Fun. is actually *ast.SelectorExpr - continue - } - if id.Name == "Label" { - ls := extractLabels(expr) - for _, label := range ls { - labels = append(labels, label) - } - } - } - } - return labels -} - -func extractLabels(expr *ast.CallExpr) []string { - out := []string{} - for _, arg := range expr.Args { - switch expr := arg.(type) { - case *ast.BasicLit: - if expr.Kind == token.STRING { - unquoted, err := strconv.Unquote(expr.Value) - if err != nil { - unquoted = expr.Value - } - validated, err := types.ValidateAndCleanupLabel(unquoted, types.CodeLocation{}) - if err == nil { - out = append(out, validated) - } - } - } - } - - return out -} - -func pendingFromCallExpr(ce *ast.CallExpr) bool { - - pending := false - if len(ce.Args) < 2 { - return pending - } - - for _, arg := range ce.Args[1:] { - switch expr := arg.(type) { - case *ast.CallExpr: - id, ok := expr.Fun.(*ast.Ident) - if !ok { - // to skip over cases where the expr.Fun. is actually *ast.SelectorExpr - continue - } - if id.Name == "Pending" { - pending = true - } - case *ast.Ident: - if expr.Name == "Pending" { - pending = true - } - } - } - return pending -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go deleted file mode 100644 index 67ec5ab757..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Most of the required functions were available in the -// "golang.org/x/tools/go/ast/astutil" package, but not exported. -// They were copied from https://github.com/golang/tools/blob/2b0845dc783e36ae26d683f4915a5840ef01ab0f/go/ast/astutil/imports.go - -package outline - -import ( - "go/ast" - "strconv" - "strings" -) - -// packageNameForImport returns the package name for the package. If the package -// is not imported, it returns nil. "Package name" refers to `pkgname` in the -// call expression `pkgname.ExportedIdentifier`. Examples: -// (import path not found) -> nil -// "import example.com/pkg/foo" -> "foo" -// "import fooalias example.com/pkg/foo" -> "fooalias" -// "import . example.com/pkg/foo" -> "" -func packageNameForImport(f *ast.File, path string) *string { - spec := importSpec(f, path) - if spec == nil { - return nil - } - name := spec.Name.String() - if name == "" { - // If the package name is not explicitly specified, - // make an educated guess. This is not guaranteed to be correct. - lastSlash := strings.LastIndex(path, "/") - if lastSlash == -1 { - name = path - } else { - name = path[lastSlash+1:] - } - } - if name == "." { - name = "" - } - return &name -} - -// importSpec returns the import spec if f imports path, -// or nil otherwise. -func importSpec(f *ast.File, path string) *ast.ImportSpec { - for _, s := range f.Imports { - if strings.HasPrefix(importPath(s), path) { - return s - } - } - return nil -} - -// importPath returns the unquoted import path of s, -// or "" if the path is not properly quoted. -func importPath(s *ast.ImportSpec) string { - t, err := strconv.Unquote(s.Path.Value) - if err != nil { - return "" - } - return t -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go deleted file mode 100644 index c2327cda8c..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go +++ /dev/null @@ -1,110 +0,0 @@ -package outline - -import ( - "encoding/json" - "fmt" - "go/ast" - "go/token" - "strings" - - "golang.org/x/tools/go/ast/inspector" -) - -const ( - // ginkgoImportPath is the well-known ginkgo import path - ginkgoImportPath = "github.com/onsi/ginkgo/v2" -) - -// FromASTFile returns an outline for a Ginkgo test source file -func FromASTFile(fset *token.FileSet, src *ast.File) (*outline, error) { - ginkgoPackageName := packageNameForImport(src, ginkgoImportPath) - if ginkgoPackageName == nil { - return nil, fmt.Errorf("file does not import %q", ginkgoImportPath) - } - - root := ginkgoNode{} - stack := []*ginkgoNode{&root} - ispr := inspector.New([]*ast.File{src}) - ispr.Nodes([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node, push bool) bool { - if push { - // Pre-order traversal - ce, ok := node.(*ast.CallExpr) - if !ok { - // Because `Nodes` calls this function only when the node is an - // ast.CallExpr, this should never happen - panic(fmt.Errorf("node starting at %d, ending at %d is not an *ast.CallExpr", node.Pos(), node.End())) - } - gn, ok := ginkgoNodeFromCallExpr(fset, ce, ginkgoPackageName) - if !ok { - // Node is not a Ginkgo spec or container, continue - return true - } - parent := stack[len(stack)-1] - parent.Nodes = append(parent.Nodes, gn) - stack = append(stack, gn) - return true - } - // Post-order traversal - start, end := absoluteOffsetsForNode(fset, node) - lastVisitedGinkgoNode := stack[len(stack)-1] - if start != lastVisitedGinkgoNode.Start || end != lastVisitedGinkgoNode.End { - // Node is not a Ginkgo spec or container, so it was not pushed onto the stack, continue - return true - } - stack = stack[0 : len(stack)-1] - return true - }) - if len(root.Nodes) == 0 { - return &outline{[]*ginkgoNode{}}, nil - } - - // Derive the final focused property for all nodes. This must be done - // _before_ propagating the inherited focused property. - root.BackpropagateUnfocus() - // Now, propagate inherited properties, including focused and pending. - root.PropagateInheritedProperties() - - return &outline{root.Nodes}, nil -} - -type outline struct { - Nodes []*ginkgoNode `json:"nodes"` -} - -func (o *outline) MarshalJSON() ([]byte, error) { - return json.Marshal(o.Nodes) -} - -// String returns a CSV-formatted outline. Spec or container are output in -// depth-first order. -func (o *outline) String() string { - return o.StringIndent(0) -} - -// StringIndent returns a CSV-formated outline, but every line is indented by -// one 'width' of spaces for every level of nesting. -func (o *outline) StringIndent(width int) string { - var b strings.Builder - b.WriteString("Name,Text,Start,End,Spec,Focused,Pending,Labels\n") - - currentIndent := 0 - pre := func(n *ginkgoNode) { - b.WriteString(fmt.Sprintf("%*s", currentIndent, "")) - var labels string - if len(n.Labels) == 1 { - labels = n.Labels[0] - } else { - labels = strings.Join(n.Labels, ", ") - } - //enclosing labels in a double quoted comma separate listed so that when inmported into a CSV app the Labels column has comma separate strings - b.WriteString(fmt.Sprintf("%s,%s,%d,%d,%t,%t,%t,\"%s\"\n", n.Name, n.Text, n.Start, n.End, n.Spec, n.Focused, n.Pending, labels)) - currentIndent += width - } - post := func(n *ginkgoNode) { - currentIndent -= width - } - for _, n := range o.Nodes { - n.Walk(pre, post) - } - return b.String() -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go deleted file mode 100644 index 36698d46a4..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go +++ /dev/null @@ -1,98 +0,0 @@ -package outline - -import ( - "encoding/json" - "fmt" - "go/parser" - "go/token" - "os" - - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/types" -) - -const ( - // indentWidth is the width used by the 'indent' output - indentWidth = 4 - // stdinAlias is a portable alias for stdin. This convention is used in - // other CLIs, e.g., kubectl. - stdinAlias = "-" - usageCommand = "ginkgo outline " -) - -type outlineConfig struct { - Format string -} - -func BuildOutlineCommand() command.Command { - conf := outlineConfig{ - Format: "csv", - } - flags, err := types.NewGinkgoFlagSet( - types.GinkgoFlags{ - {Name: "format", KeyPath: "Format", - Usage: "Format of outline", - UsageArgument: "one of 'csv', 'indent', or 'json'", - UsageDefaultValue: conf.Format, - }, - }, - &conf, - types.GinkgoFlagSections{}, - ) - if err != nil { - panic(err) - } - - return command.Command{ - Name: "outline", - Usage: "ginkgo outline ", - ShortDoc: "Create an outline of Ginkgo symbols for a file", - Documentation: "To read from stdin, use: `ginkgo outline -`", - DocLink: "creating-an-outline-of-specs", - Flags: flags, - Command: func(args []string, _ []string) { - outlineFile(args, conf.Format) - }, - } -} - -func outlineFile(args []string, format string) { - if len(args) != 1 { - command.AbortWithUsage("outline expects exactly one argument") - } - - filename := args[0] - var src *os.File - if filename == stdinAlias { - src = os.Stdin - } else { - var err error - src, err = os.Open(filename) - command.AbortIfError("Failed to open file:", err) - } - - fset := token.NewFileSet() - - parsedSrc, err := parser.ParseFile(fset, filename, src, 0) - command.AbortIfError("Failed to parse source:", err) - - o, err := FromASTFile(fset, parsedSrc) - command.AbortIfError("Failed to create outline:", err) - - var oerr error - switch format { - case "csv": - _, oerr = fmt.Print(o) - case "indent": - _, oerr = fmt.Print(o.StringIndent(indentWidth)) - case "json": - b, err := json.Marshal(o) - if err != nil { - println(fmt.Sprintf("error marshalling to json: %s", err)) - } - _, oerr = fmt.Println(string(b)) - default: - command.AbortWith("Format %s not accepted", format) - } - command.AbortIfError("Failed to write outline:", oerr) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go deleted file mode 100644 index aaed4d570e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go +++ /dev/null @@ -1,232 +0,0 @@ -package run - -import ( - "fmt" - "os" - "strings" - "time" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/internal/interrupt_handler" - "github.com/onsi/ginkgo/v2/types" -) - -func BuildRunCommand() command.Command { - var suiteConfig = types.NewDefaultSuiteConfig() - var reporterConfig = types.NewDefaultReporterConfig() - var cliConfig = types.NewDefaultCLIConfig() - var goFlagsConfig = types.NewDefaultGoFlagsConfig() - - flags, err := types.BuildRunCommandFlagSet(&suiteConfig, &reporterConfig, &cliConfig, &goFlagsConfig) - if err != nil { - panic(err) - } - - interruptHandler := interrupt_handler.NewInterruptHandler(nil) - interrupt_handler.SwallowSigQuit() - - return command.Command{ - Name: "run", - Flags: flags, - Usage: "ginkgo run -- ", - ShortDoc: "Run the tests in the passed in (or the package in the current directory if left blank)", - Documentation: "Any arguments after -- will be passed to the test.", - DocLink: "running-tests", - Command: func(args []string, additionalArgs []string) { - var errors []error - cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) - command.AbortIfErrors("Ginkgo detected configuration issues:", errors) - - runner := &SpecRunner{ - cliConfig: cliConfig, - goFlagsConfig: goFlagsConfig, - suiteConfig: suiteConfig, - reporterConfig: reporterConfig, - flags: flags, - - interruptHandler: interruptHandler, - } - - runner.RunSpecs(args, additionalArgs) - }, - } -} - -type SpecRunner struct { - suiteConfig types.SuiteConfig - reporterConfig types.ReporterConfig - cliConfig types.CLIConfig - goFlagsConfig types.GoFlagsConfig - flags types.GinkgoFlagSet - - interruptHandler *interrupt_handler.InterruptHandler -} - -func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { - suites := internal.FindSuites(args, r.cliConfig, true) - skippedSuites := suites.WithState(internal.TestSuiteStateSkippedByFilter) - suites = suites.WithoutState(internal.TestSuiteStateSkippedByFilter) - - internal.VerifyCLIAndFrameworkVersion(suites) - - if len(skippedSuites) > 0 { - fmt.Println("Will skip:") - for _, skippedSuite := range skippedSuites { - fmt.Println(" " + skippedSuite.Path) - } - } - - if len(skippedSuites) > 0 && len(suites) == 0 { - command.AbortGracefullyWith("All tests skipped! Exiting...") - } - - if len(suites) == 0 { - command.AbortWith("Found no test suites") - } - - if len(suites) > 1 && !r.flags.WasSet("succinct") && r.reporterConfig.Verbosity().LT(types.VerbosityLevelVerbose) { - r.reporterConfig.Succinct = true - } - - t := time.Now() - var endTime time.Time - if r.suiteConfig.Timeout > 0 { - endTime = t.Add(r.suiteConfig.Timeout) - } - - iteration := 0 -OUTER_LOOP: - for { - if !r.flags.WasSet("seed") { - r.suiteConfig.RandomSeed = time.Now().Unix() - } - if r.cliConfig.RandomizeSuites && len(suites) > 1 { - suites = suites.ShuffledCopy(r.suiteConfig.RandomSeed) - } - - opc := internal.NewOrderedParallelCompiler(r.cliConfig.ComputedNumCompilers()) - opc.StartCompiling(suites, r.goFlagsConfig) - - SUITE_LOOP: - for { - suiteIdx, suite := opc.Next() - if suiteIdx >= len(suites) { - break SUITE_LOOP - } - suites[suiteIdx] = suite - - if r.interruptHandler.Status().Interrupted() { - opc.StopAndDrain() - break OUTER_LOOP - } - - if suites[suiteIdx].State.Is(internal.TestSuiteStateSkippedDueToEmptyCompilation) { - fmt.Printf("Skipping %s (no test files)\n", suite.Path) - continue SUITE_LOOP - } - - if suites[suiteIdx].State.Is(internal.TestSuiteStateFailedToCompile) { - fmt.Println(suites[suiteIdx].CompilationError.Error()) - if !r.cliConfig.KeepGoing { - opc.StopAndDrain() - } - continue SUITE_LOOP - } - - if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 && !r.cliConfig.KeepGoing { - suites[suiteIdx].State = internal.TestSuiteStateSkippedDueToPriorFailures - opc.StopAndDrain() - continue SUITE_LOOP - } - - if !endTime.IsZero() { - r.suiteConfig.Timeout = endTime.Sub(time.Now()) - if r.suiteConfig.Timeout <= 0 { - suites[suiteIdx].State = internal.TestSuiteStateFailedDueToTimeout - opc.StopAndDrain() - continue SUITE_LOOP - } - } - - suites[suiteIdx] = internal.RunCompiledSuite(suites[suiteIdx], r.suiteConfig, r.reporterConfig, r.cliConfig, r.goFlagsConfig, additionalArgs) - } - - if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { - if iteration > 0 { - fmt.Printf("\nTests failed on attempt #%d\n\n", iteration+1) - } - break OUTER_LOOP - } - - if r.cliConfig.UntilItFails { - fmt.Printf("\nAll tests passed...\nWill keep running them until they fail.\nThis was attempt #%d\n%s\n", iteration+1, orcMessage(iteration+1)) - } else if r.cliConfig.Repeat > 0 && iteration < r.cliConfig.Repeat { - fmt.Printf("\nAll tests passed...\nThis was attempt %d of %d.\n", iteration+1, r.cliConfig.Repeat+1) - } else { - break OUTER_LOOP - } - iteration += 1 - } - - internal.Cleanup(r.goFlagsConfig, suites...) - - messages, err := internal.FinalizeProfilesAndReportsForSuites(suites, r.cliConfig, r.suiteConfig, r.reporterConfig, r.goFlagsConfig) - command.AbortIfError("could not finalize profiles:", err) - for _, message := range messages { - fmt.Println(message) - } - - fmt.Printf("\nGinkgo ran %d %s in %s\n", len(suites), internal.PluralizedWord("suite", "suites", len(suites)), time.Since(t)) - - if suites.CountWithState(internal.TestSuiteStateFailureStates...) == 0 { - if suites.AnyHaveProgrammaticFocus() && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { - fmt.Printf("Test Suite Passed\n") - fmt.Printf("Detected Programmatic Focus - setting exit status to %d\n", types.GINKGO_FOCUS_EXIT_CODE) - command.Abort(command.AbortDetails{ExitCode: types.GINKGO_FOCUS_EXIT_CODE}) - } else { - fmt.Printf("Test Suite Passed\n") - command.Abort(command.AbortDetails{}) - } - } else { - fmt.Fprintln(formatter.ColorableStdOut, "") - if len(suites) > 1 && suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { - fmt.Fprintln(formatter.ColorableStdOut, - internal.FailedSuitesReport(suites, formatter.NewWithNoColorBool(r.reporterConfig.NoColor))) - } - fmt.Printf("Test Suite Failed\n") - command.Abort(command.AbortDetails{ExitCode: 1}) - } -} - -func orcMessage(iteration int) string { - if iteration < 10 { - return "" - } else if iteration < 30 { - return []string{ - "If at first you succeed...", - "...try, try again.", - "Looking good!", - "Still good...", - "I think your tests are fine....", - "Yep, still passing", - "Oh boy, here I go testin' again!", - "Even the gophers are getting bored", - "Did you try -race?", - "Maybe you should stop now?", - "I'm getting tired...", - "What if I just made you a sandwich?", - "Hit ^C, hit ^C, please hit ^C", - "Make it stop. Please!", - "Come on! Enough is enough!", - "Dave, this conversation can serve no purpose anymore. Goodbye.", - "Just what do you think you're doing, Dave? ", - "I, Sisyphus", - "Insanity: doing the same thing over and over again and expecting different results. -Einstein", - "I guess Einstein never tried to churn butter", - }[iteration-10] + "\n" - } else { - return "No, seriously... you can probably stop now.\n" - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go deleted file mode 100644 index 7dd2943948..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go +++ /dev/null @@ -1,186 +0,0 @@ -package unfocus - -import ( - "bytes" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io" - "os" - "path/filepath" - "strings" - "sync" - - "github.com/onsi/ginkgo/v2/ginkgo/command" -) - -func BuildUnfocusCommand() command.Command { - return command.Command{ - Name: "unfocus", - Usage: "ginkgo unfocus", - ShortDoc: "Recursively unfocus any focused tests under the current directory", - DocLink: "filtering-specs", - Command: func(_ []string, _ []string) { - unfocusSpecs() - }, - } -} - -func unfocusSpecs() { - fmt.Println("Scanning for focus...") - - goFiles := make(chan string) - go func() { - unfocusDir(goFiles, ".") - close(goFiles) - }() - - const workers = 10 - wg := sync.WaitGroup{} - wg.Add(workers) - - for i := 0; i < workers; i++ { - go func() { - for path := range goFiles { - unfocusFile(path) - } - wg.Done() - }() - } - - wg.Wait() -} - -func unfocusDir(goFiles chan string, path string) { - files, err := os.ReadDir(path) - if err != nil { - fmt.Println(err.Error()) - return - } - - for _, f := range files { - switch { - case f.IsDir() && shouldProcessDir(f.Name()): - unfocusDir(goFiles, filepath.Join(path, f.Name())) - case !f.IsDir() && shouldProcessFile(f.Name()): - goFiles <- filepath.Join(path, f.Name()) - } - } -} - -func shouldProcessDir(basename string) bool { - return basename != "vendor" && !strings.HasPrefix(basename, ".") -} - -func shouldProcessFile(basename string) bool { - return strings.HasSuffix(basename, ".go") -} - -func unfocusFile(path string) { - data, err := os.ReadFile(path) - if err != nil { - fmt.Printf("error reading file '%s': %s\n", path, err.Error()) - return - } - - ast, err := parser.ParseFile(token.NewFileSet(), path, bytes.NewReader(data), parser.ParseComments) - if err != nil { - fmt.Printf("error parsing file '%s': %s\n", path, err.Error()) - return - } - - eliminations := scanForFocus(ast) - if len(eliminations) == 0 { - return - } - - fmt.Printf("...updating %s\n", path) - backup, err := writeBackup(path, data) - if err != nil { - fmt.Printf("error creating backup file: %s\n", err.Error()) - return - } - - if err := updateFile(path, data, eliminations); err != nil { - fmt.Printf("error writing file '%s': %s\n", path, err.Error()) - return - } - - os.Remove(backup) -} - -func writeBackup(path string, data []byte) (string, error) { - t, err := os.CreateTemp(filepath.Dir(path), filepath.Base(path)) - - if err != nil { - return "", fmt.Errorf("error creating temporary file: %w", err) - } - defer t.Close() - - if _, err := io.Copy(t, bytes.NewReader(data)); err != nil { - return "", fmt.Errorf("error writing to temporary file: %w", err) - } - - return t.Name(), nil -} - -func updateFile(path string, data []byte, eliminations [][]int64) error { - to, err := os.Create(path) - if err != nil { - return fmt.Errorf("error opening file for writing '%s': %w\n", path, err) - } - defer to.Close() - - from := bytes.NewReader(data) - var cursor int64 - for _, eliminationRange := range eliminations { - positionToEliminate, lengthToEliminate := eliminationRange[0]-1, eliminationRange[1] - if _, err := io.CopyN(to, from, positionToEliminate-cursor); err != nil { - return fmt.Errorf("error copying data: %w", err) - } - - cursor = positionToEliminate + lengthToEliminate - - if _, err := from.Seek(lengthToEliminate, io.SeekCurrent); err != nil { - return fmt.Errorf("error seeking to position in buffer: %w", err) - } - } - - if _, err := io.Copy(to, from); err != nil { - return fmt.Errorf("error copying end data: %w", err) - } - - return nil -} - -func scanForFocus(file *ast.File) (eliminations [][]int64) { - ast.Inspect(file, func(n ast.Node) bool { - if c, ok := n.(*ast.CallExpr); ok { - if i, ok := c.Fun.(*ast.Ident); ok { - if isFocus(i.Name) { - eliminations = append(eliminations, []int64{int64(i.Pos()), 1}) - } - } - } - - if i, ok := n.(*ast.Ident); ok { - if i.Name == "Focus" { - eliminations = append(eliminations, []int64{int64(i.Pos()), 6}) - } - } - - return true - }) - - return eliminations -} - -func isFocus(name string) bool { - switch name { - case "FDescribe", "FContext", "FIt", "FDescribeTable", "FEntry", "FSpecify", "FWhen": - return true - default: - return false - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go deleted file mode 100644 index 6c485c5b1a..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go +++ /dev/null @@ -1,22 +0,0 @@ -package watch - -import "sort" - -type Delta struct { - ModifiedPackages []string - - NewSuites []*Suite - RemovedSuites []*Suite - modifiedSuites []*Suite -} - -type DescendingByDelta []*Suite - -func (a DescendingByDelta) Len() int { return len(a) } -func (a DescendingByDelta) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a DescendingByDelta) Less(i, j int) bool { return a[i].Delta() > a[j].Delta() } - -func (d Delta) ModifiedSuites() []*Suite { - sort.Sort(DescendingByDelta(d.modifiedSuites)) - return d.modifiedSuites -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go deleted file mode 100644 index 26418ac62e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go +++ /dev/null @@ -1,75 +0,0 @@ -package watch - -import ( - "fmt" - - "regexp" - - "github.com/onsi/ginkgo/v2/ginkgo/internal" -) - -type SuiteErrors map[internal.TestSuite]error - -type DeltaTracker struct { - maxDepth int - watchRegExp *regexp.Regexp - suites map[string]*Suite - packageHashes *PackageHashes -} - -func NewDeltaTracker(maxDepth int, watchRegExp *regexp.Regexp) *DeltaTracker { - return &DeltaTracker{ - maxDepth: maxDepth, - watchRegExp: watchRegExp, - packageHashes: NewPackageHashes(watchRegExp), - suites: map[string]*Suite{}, - } -} - -func (d *DeltaTracker) Delta(suites internal.TestSuites) (delta Delta, errors SuiteErrors) { - errors = SuiteErrors{} - delta.ModifiedPackages = d.packageHashes.CheckForChanges() - - providedSuitePaths := map[string]bool{} - for _, suite := range suites { - providedSuitePaths[suite.Path] = true - } - - d.packageHashes.StartTrackingUsage() - - for _, suite := range d.suites { - if providedSuitePaths[suite.Suite.Path] { - if suite.Delta() > 0 { - delta.modifiedSuites = append(delta.modifiedSuites, suite) - } - } else { - delta.RemovedSuites = append(delta.RemovedSuites, suite) - } - } - - d.packageHashes.StopTrackingUsageAndPrune() - - for _, suite := range suites { - _, ok := d.suites[suite.Path] - if !ok { - s, err := NewSuite(suite, d.maxDepth, d.packageHashes) - if err != nil { - errors[suite] = err - continue - } - d.suites[suite.Path] = s - delta.NewSuites = append(delta.NewSuites, s) - } - } - - return delta, errors -} - -func (d *DeltaTracker) WillRun(suite internal.TestSuite) error { - s, ok := d.suites[suite.Path] - if !ok { - return fmt.Errorf("unknown suite %s", suite.Path) - } - - return s.MarkAsRunAndRecomputedDependencies(d.maxDepth) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go deleted file mode 100644 index f5ddff30fc..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go +++ /dev/null @@ -1,92 +0,0 @@ -package watch - -import ( - "go/build" - "regexp" -) - -var ginkgoAndGomegaFilter = regexp.MustCompile(`github\.com/onsi/ginkgo|github\.com/onsi/gomega`) -var ginkgoIntegrationTestFilter = regexp.MustCompile(`github\.com/onsi/ginkgo/integration`) //allow us to integration test this thing - -type Dependencies struct { - deps map[string]int -} - -func NewDependencies(path string, maxDepth int) (Dependencies, error) { - d := Dependencies{ - deps: map[string]int{}, - } - - if maxDepth == 0 { - return d, nil - } - - err := d.seedWithDepsForPackageAtPath(path) - if err != nil { - return d, err - } - - for depth := 1; depth < maxDepth; depth++ { - n := len(d.deps) - d.addDepsForDepth(depth) - if n == len(d.deps) { - break - } - } - - return d, nil -} - -func (d Dependencies) Dependencies() map[string]int { - return d.deps -} - -func (d Dependencies) seedWithDepsForPackageAtPath(path string) error { - pkg, err := build.ImportDir(path, 0) - if err != nil { - return err - } - - d.resolveAndAdd(pkg.Imports, 1) - d.resolveAndAdd(pkg.TestImports, 1) - d.resolveAndAdd(pkg.XTestImports, 1) - - delete(d.deps, pkg.Dir) - return nil -} - -func (d Dependencies) addDepsForDepth(depth int) { - for dep, depDepth := range d.deps { - if depDepth == depth { - d.addDepsForDep(dep, depth+1) - } - } -} - -func (d Dependencies) addDepsForDep(dep string, depth int) { - pkg, err := build.ImportDir(dep, 0) - if err != nil { - println(err.Error()) - return - } - d.resolveAndAdd(pkg.Imports, depth) -} - -func (d Dependencies) resolveAndAdd(deps []string, depth int) { - for _, dep := range deps { - pkg, err := build.Import(dep, ".", 0) - if err != nil { - continue - } - if !pkg.Goroot && (!ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) || ginkgoIntegrationTestFilter.Match([]byte(pkg.Dir))) { - d.addDepIfNotPresent(pkg.Dir, depth) - } - } -} - -func (d Dependencies) addDepIfNotPresent(dep string, depth int) { - _, ok := d.deps[dep] - if !ok { - d.deps[dep] = depth - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go deleted file mode 100644 index e9f7ec0cb3..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go +++ /dev/null @@ -1,108 +0,0 @@ -package watch - -import ( - "fmt" - "os" - "regexp" - "time" -) - -var goTestRegExp = regexp.MustCompile(`_test\.go$`) - -type PackageHash struct { - CodeModifiedTime time.Time - TestModifiedTime time.Time - Deleted bool - - path string - codeHash string - testHash string - watchRegExp *regexp.Regexp -} - -func NewPackageHash(path string, watchRegExp *regexp.Regexp) *PackageHash { - p := &PackageHash{ - path: path, - watchRegExp: watchRegExp, - } - - p.codeHash, _, p.testHash, _, p.Deleted = p.computeHashes() - - return p -} - -func (p *PackageHash) CheckForChanges() bool { - codeHash, codeModifiedTime, testHash, testModifiedTime, deleted := p.computeHashes() - - if deleted { - if !p.Deleted { - t := time.Now() - p.CodeModifiedTime = t - p.TestModifiedTime = t - } - p.Deleted = true - return true - } - - modified := false - p.Deleted = false - - if p.codeHash != codeHash { - p.CodeModifiedTime = codeModifiedTime - modified = true - } - if p.testHash != testHash { - p.TestModifiedTime = testModifiedTime - modified = true - } - - p.codeHash = codeHash - p.testHash = testHash - return modified -} - -func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Time, testHash string, testModifiedTime time.Time, deleted bool) { - entries, err := os.ReadDir(p.path) - - if err != nil { - deleted = true - return - } - - for _, entry := range entries { - if entry.IsDir() { - continue - } - - info, err := entry.Info() - if err != nil { - continue - } - - if goTestRegExp.Match([]byte(info.Name())) { - testHash += p.hashForFileInfo(info) - if info.ModTime().After(testModifiedTime) { - testModifiedTime = info.ModTime() - } - continue - } - - if p.watchRegExp.Match([]byte(info.Name())) { - codeHash += p.hashForFileInfo(info) - if info.ModTime().After(codeModifiedTime) { - codeModifiedTime = info.ModTime() - } - } - } - - testHash += codeHash - if codeModifiedTime.After(testModifiedTime) { - testModifiedTime = codeModifiedTime - } - - return -} - -func (p *PackageHash) hashForFileInfo(info os.FileInfo) string { - return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano()) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go deleted file mode 100644 index b4892bebf2..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go +++ /dev/null @@ -1,85 +0,0 @@ -package watch - -import ( - "path/filepath" - "regexp" - "sync" -) - -type PackageHashes struct { - PackageHashes map[string]*PackageHash - usedPaths map[string]bool - watchRegExp *regexp.Regexp - lock *sync.Mutex -} - -func NewPackageHashes(watchRegExp *regexp.Regexp) *PackageHashes { - return &PackageHashes{ - PackageHashes: map[string]*PackageHash{}, - usedPaths: nil, - watchRegExp: watchRegExp, - lock: &sync.Mutex{}, - } -} - -func (p *PackageHashes) CheckForChanges() []string { - p.lock.Lock() - defer p.lock.Unlock() - - modified := []string{} - - for _, packageHash := range p.PackageHashes { - if packageHash.CheckForChanges() { - modified = append(modified, packageHash.path) - } - } - - return modified -} - -func (p *PackageHashes) Add(path string) *PackageHash { - p.lock.Lock() - defer p.lock.Unlock() - - path, _ = filepath.Abs(path) - _, ok := p.PackageHashes[path] - if !ok { - p.PackageHashes[path] = NewPackageHash(path, p.watchRegExp) - } - - if p.usedPaths != nil { - p.usedPaths[path] = true - } - return p.PackageHashes[path] -} - -func (p *PackageHashes) Get(path string) *PackageHash { - p.lock.Lock() - defer p.lock.Unlock() - - path, _ = filepath.Abs(path) - if p.usedPaths != nil { - p.usedPaths[path] = true - } - return p.PackageHashes[path] -} - -func (p *PackageHashes) StartTrackingUsage() { - p.lock.Lock() - defer p.lock.Unlock() - - p.usedPaths = map[string]bool{} -} - -func (p *PackageHashes) StopTrackingUsageAndPrune() { - p.lock.Lock() - defer p.lock.Unlock() - - for path := range p.PackageHashes { - if !p.usedPaths[path] { - delete(p.PackageHashes, path) - } - } - - p.usedPaths = nil -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go deleted file mode 100644 index 53272df7e5..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go +++ /dev/null @@ -1,87 +0,0 @@ -package watch - -import ( - "fmt" - "math" - "time" - - "github.com/onsi/ginkgo/v2/ginkgo/internal" -) - -type Suite struct { - Suite internal.TestSuite - RunTime time.Time - Dependencies Dependencies - - sharedPackageHashes *PackageHashes -} - -func NewSuite(suite internal.TestSuite, maxDepth int, sharedPackageHashes *PackageHashes) (*Suite, error) { - deps, err := NewDependencies(suite.Path, maxDepth) - if err != nil { - return nil, err - } - - sharedPackageHashes.Add(suite.Path) - for dep := range deps.Dependencies() { - sharedPackageHashes.Add(dep) - } - - return &Suite{ - Suite: suite, - Dependencies: deps, - - sharedPackageHashes: sharedPackageHashes, - }, nil -} - -func (s *Suite) Delta() float64 { - delta := s.delta(s.Suite.Path, true, 0) * 1000 - for dep, depth := range s.Dependencies.Dependencies() { - delta += s.delta(dep, false, depth) - } - return delta -} - -func (s *Suite) MarkAsRunAndRecomputedDependencies(maxDepth int) error { - s.RunTime = time.Now() - - deps, err := NewDependencies(s.Suite.Path, maxDepth) - if err != nil { - return err - } - - s.sharedPackageHashes.Add(s.Suite.Path) - for dep := range deps.Dependencies() { - s.sharedPackageHashes.Add(dep) - } - - s.Dependencies = deps - - return nil -} - -func (s *Suite) Description() string { - numDeps := len(s.Dependencies.Dependencies()) - pluralizer := "ies" - if numDeps == 1 { - pluralizer = "y" - } - return fmt.Sprintf("%s [%d dependenc%s]", s.Suite.Path, numDeps, pluralizer) -} - -func (s *Suite) delta(packagePath string, includeTests bool, depth int) float64 { - return math.Max(float64(s.dt(packagePath, includeTests)), 0) / float64(depth+1) -} - -func (s *Suite) dt(packagePath string, includeTests bool) time.Duration { - packageHash := s.sharedPackageHashes.Get(packagePath) - var modifiedTime time.Time - if includeTests { - modifiedTime = packageHash.TestModifiedTime - } else { - modifiedTime = packageHash.CodeModifiedTime - } - - return modifiedTime.Sub(s.RunTime) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go deleted file mode 100644 index bde4193ce7..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go +++ /dev/null @@ -1,192 +0,0 @@ -package watch - -import ( - "fmt" - "regexp" - "time" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/ginkgo/command" - "github.com/onsi/ginkgo/v2/ginkgo/internal" - "github.com/onsi/ginkgo/v2/internal/interrupt_handler" - "github.com/onsi/ginkgo/v2/types" -) - -func BuildWatchCommand() command.Command { - var suiteConfig = types.NewDefaultSuiteConfig() - var reporterConfig = types.NewDefaultReporterConfig() - var cliConfig = types.NewDefaultCLIConfig() - var goFlagsConfig = types.NewDefaultGoFlagsConfig() - - flags, err := types.BuildWatchCommandFlagSet(&suiteConfig, &reporterConfig, &cliConfig, &goFlagsConfig) - if err != nil { - panic(err) - } - interruptHandler := interrupt_handler.NewInterruptHandler(nil) - interrupt_handler.SwallowSigQuit() - - return command.Command{ - Name: "watch", - Flags: flags, - Usage: "ginkgo watch -- ", - ShortDoc: "Watch the passed in and runs their tests whenever changes occur.", - Documentation: "Any arguments after -- will be passed to the test.", - DocLink: "watching-for-changes", - Command: func(args []string, additionalArgs []string) { - var errors []error - cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) - command.AbortIfErrors("Ginkgo detected configuration issues:", errors) - - watcher := &SpecWatcher{ - cliConfig: cliConfig, - goFlagsConfig: goFlagsConfig, - suiteConfig: suiteConfig, - reporterConfig: reporterConfig, - flags: flags, - - interruptHandler: interruptHandler, - } - - watcher.WatchSpecs(args, additionalArgs) - }, - } -} - -type SpecWatcher struct { - suiteConfig types.SuiteConfig - reporterConfig types.ReporterConfig - cliConfig types.CLIConfig - goFlagsConfig types.GoFlagsConfig - flags types.GinkgoFlagSet - - interruptHandler *interrupt_handler.InterruptHandler -} - -func (w *SpecWatcher) WatchSpecs(args []string, additionalArgs []string) { - suites := internal.FindSuites(args, w.cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) - - internal.VerifyCLIAndFrameworkVersion(suites) - - if len(suites) == 0 { - command.AbortWith("Found no test suites") - } - - fmt.Printf("Identified %d test %s. Locating dependencies to a depth of %d (this may take a while)...\n", len(suites), internal.PluralizedWord("suite", "suites", len(suites)), w.cliConfig.Depth) - deltaTracker := NewDeltaTracker(w.cliConfig.Depth, regexp.MustCompile(w.cliConfig.WatchRegExp)) - delta, errors := deltaTracker.Delta(suites) - - fmt.Printf("Watching %d %s:\n", len(delta.NewSuites), internal.PluralizedWord("suite", "suites", len(delta.NewSuites))) - for _, suite := range delta.NewSuites { - fmt.Println(" " + suite.Description()) - } - - for suite, err := range errors { - fmt.Printf("Failed to watch %s: %s\n", suite.PackageName, err) - } - - if len(suites) == 1 { - w.updateSeed() - w.compileAndRun(suites[0], additionalArgs) - } - - ticker := time.NewTicker(time.Second) - - for { - select { - case <-ticker.C: - suites := internal.FindSuites(args, w.cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) - delta, _ := deltaTracker.Delta(suites) - coloredStream := formatter.ColorableStdOut - - suites = internal.TestSuites{} - - if len(delta.NewSuites) > 0 { - fmt.Fprintln(coloredStream, formatter.F("{{green}}Detected %d new %s:{{/}}", len(delta.NewSuites), internal.PluralizedWord("suite", "suites", len(delta.NewSuites)))) - for _, suite := range delta.NewSuites { - suites = append(suites, suite.Suite) - fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", suite.Description())) - } - } - - modifiedSuites := delta.ModifiedSuites() - if len(modifiedSuites) > 0 { - fmt.Fprintln(coloredStream, formatter.F("{{green}}Detected changes in:{{/}}")) - for _, pkg := range delta.ModifiedPackages { - fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", pkg)) - } - fmt.Fprintln(coloredStream, formatter.F("{{green}}Will run %d %s:{{/}}", len(modifiedSuites), internal.PluralizedWord("suite", "suites", len(modifiedSuites)))) - for _, suite := range modifiedSuites { - suites = append(suites, suite.Suite) - fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", suite.Description())) - } - fmt.Fprintln(coloredStream, "") - } - - if len(suites) == 0 { - break - } - - w.updateSeed() - w.computeSuccinctMode(len(suites)) - for idx := range suites { - if w.interruptHandler.Status().Interrupted() { - return - } - deltaTracker.WillRun(suites[idx]) - suites[idx] = w.compileAndRun(suites[idx], additionalArgs) - } - color := "{{green}}" - if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { - color = "{{red}}" - } - fmt.Fprintln(coloredStream, formatter.F(color+"\nDone. Resuming watch...{{/}}")) - - messages, err := internal.FinalizeProfilesAndReportsForSuites(suites, w.cliConfig, w.suiteConfig, w.reporterConfig, w.goFlagsConfig) - command.AbortIfError("could not finalize profiles:", err) - for _, message := range messages { - fmt.Println(message) - } - case <-w.interruptHandler.Status().Channel: - return - } - } -} - -func (w *SpecWatcher) compileAndRun(suite internal.TestSuite, additionalArgs []string) internal.TestSuite { - suite = internal.CompileSuite(suite, w.goFlagsConfig) - if suite.State.Is(internal.TestSuiteStateFailedToCompile) { - fmt.Println(suite.CompilationError.Error()) - return suite - } - if w.interruptHandler.Status().Interrupted() { - return suite - } - suite = internal.RunCompiledSuite(suite, w.suiteConfig, w.reporterConfig, w.cliConfig, w.goFlagsConfig, additionalArgs) - internal.Cleanup(w.goFlagsConfig, suite) - return suite -} - -func (w *SpecWatcher) computeSuccinctMode(numSuites int) { - if w.reporterConfig.Verbosity().GTE(types.VerbosityLevelVerbose) { - w.reporterConfig.Succinct = false - return - } - - if w.flags.WasSet("succinct") { - return - } - - if numSuites == 1 { - w.reporterConfig.Succinct = false - } - - if numSuites > 1 { - w.reporterConfig.Succinct = true - } -} - -func (w *SpecWatcher) updateSeed() { - if !w.flags.WasSet("seed") { - w.suiteConfig.RandomSeed = time.Now().Unix() - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go deleted file mode 100644 index 8ed86111f7..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go +++ /dev/null @@ -1,177 +0,0 @@ -package interrupt_handler - -import ( - "os" - "os/signal" - "sync" - "syscall" - "time" - - "github.com/onsi/ginkgo/v2/internal/parallel_support" -) - -var ABORT_POLLING_INTERVAL = 500 * time.Millisecond - -type InterruptCause uint - -const ( - InterruptCauseInvalid InterruptCause = iota - InterruptCauseSignal - InterruptCauseAbortByOtherProcess -) - -type InterruptLevel uint - -const ( - InterruptLevelUninterrupted InterruptLevel = iota - InterruptLevelCleanupAndReport - InterruptLevelReportOnly - InterruptLevelBailOut -) - -func (ic InterruptCause) String() string { - switch ic { - case InterruptCauseSignal: - return "Interrupted by User" - case InterruptCauseAbortByOtherProcess: - return "Interrupted by Other Ginkgo Process" - } - return "INVALID_INTERRUPT_CAUSE" -} - -type InterruptStatus struct { - Channel chan interface{} - Level InterruptLevel - Cause InterruptCause -} - -func (s InterruptStatus) Interrupted() bool { - return s.Level != InterruptLevelUninterrupted -} - -func (s InterruptStatus) Message() string { - return s.Cause.String() -} - -func (s InterruptStatus) ShouldIncludeProgressReport() bool { - return s.Cause != InterruptCauseAbortByOtherProcess -} - -type InterruptHandlerInterface interface { - Status() InterruptStatus -} - -type InterruptHandler struct { - c chan interface{} - lock *sync.Mutex - level InterruptLevel - cause InterruptCause - client parallel_support.Client - stop chan interface{} - signals []os.Signal - requestAbortCheck chan interface{} -} - -func NewInterruptHandler(client parallel_support.Client, signals ...os.Signal) *InterruptHandler { - if len(signals) == 0 { - signals = []os.Signal{os.Interrupt, syscall.SIGTERM} - } - handler := &InterruptHandler{ - c: make(chan interface{}), - lock: &sync.Mutex{}, - stop: make(chan interface{}), - requestAbortCheck: make(chan interface{}), - client: client, - signals: signals, - } - handler.registerForInterrupts() - return handler -} - -func (handler *InterruptHandler) Stop() { - close(handler.stop) -} - -func (handler *InterruptHandler) registerForInterrupts() { - // os signal handling - signalChannel := make(chan os.Signal, 1) - signal.Notify(signalChannel, handler.signals...) - - // cross-process abort handling - var abortChannel chan interface{} - if handler.client != nil { - abortChannel = make(chan interface{}) - go func() { - pollTicker := time.NewTicker(ABORT_POLLING_INTERVAL) - for { - select { - case <-pollTicker.C: - if handler.client.ShouldAbort() { - close(abortChannel) - pollTicker.Stop() - return - } - case <-handler.requestAbortCheck: - if handler.client.ShouldAbort() { - close(abortChannel) - pollTicker.Stop() - return - } - case <-handler.stop: - pollTicker.Stop() - return - } - } - }() - } - - go func(abortChannel chan interface{}) { - var interruptCause InterruptCause - for { - select { - case <-signalChannel: - interruptCause = InterruptCauseSignal - case <-abortChannel: - interruptCause = InterruptCauseAbortByOtherProcess - case <-handler.stop: - signal.Stop(signalChannel) - return - } - abortChannel = nil - - handler.lock.Lock() - oldLevel := handler.level - handler.cause = interruptCause - if handler.level == InterruptLevelUninterrupted { - handler.level = InterruptLevelCleanupAndReport - } else if handler.level == InterruptLevelCleanupAndReport { - handler.level = InterruptLevelReportOnly - } else if handler.level == InterruptLevelReportOnly { - handler.level = InterruptLevelBailOut - } - if handler.level != oldLevel { - close(handler.c) - handler.c = make(chan interface{}) - } - handler.lock.Unlock() - } - }(abortChannel) -} - -func (handler *InterruptHandler) Status() InterruptStatus { - handler.lock.Lock() - status := InterruptStatus{ - Level: handler.level, - Channel: handler.c, - Cause: handler.cause, - } - handler.lock.Unlock() - - if handler.client != nil && handler.client.ShouldAbort() && !status.Interrupted() { - close(handler.requestAbortCheck) - <-status.Channel - return handler.Status() - } - - return status -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go deleted file mode 100644 index bf0de496dc..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build freebsd || openbsd || netbsd || dragonfly || darwin || linux || solaris -// +build freebsd openbsd netbsd dragonfly darwin linux solaris - -package interrupt_handler - -import ( - "os" - "os/signal" - "syscall" -) - -func SwallowSigQuit() { - c := make(chan os.Signal, 1024) - signal.Notify(c, syscall.SIGQUIT) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go deleted file mode 100644 index fcf8da8335..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build windows -// +build windows - -package interrupt_handler - -func SwallowSigQuit() { - //noop -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go deleted file mode 100644 index b3cd64292a..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go +++ /dev/null @@ -1,72 +0,0 @@ -package parallel_support - -import ( - "fmt" - "io" - "os" - "time" - - "github.com/onsi/ginkgo/v2/reporters" - "github.com/onsi/ginkgo/v2/types" -) - -type BeforeSuiteState struct { - Data []byte - State types.SpecState -} - -type ParallelIndexCounter struct { - Index int -} - -var ErrorGone = fmt.Errorf("gone") -var ErrorFailed = fmt.Errorf("failed") -var ErrorEarly = fmt.Errorf("early") - -var POLLING_INTERVAL = 50 * time.Millisecond - -type Server interface { - Start() - Close() - Address() string - RegisterAlive(node int, alive func() bool) - GetSuiteDone() chan interface{} - GetOutputDestination() io.Writer - SetOutputDestination(io.Writer) -} - -type Client interface { - Connect() bool - Close() error - - PostSuiteWillBegin(report types.Report) error - PostDidRun(report types.SpecReport) error - PostSuiteDidEnd(report types.Report) error - PostReportBeforeSuiteCompleted(state types.SpecState) error - BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) - PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error - BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) - BlockUntilNonprimaryProcsHaveFinished() error - BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) - FetchNextCounter() (int, error) - PostAbort() error - ShouldAbort() bool - PostEmitProgressReport(report types.ProgressReport) error - Write(p []byte) (int, error) -} - -func NewServer(parallelTotal int, reporter reporters.Reporter) (Server, error) { - if os.Getenv("GINKGO_PARALLEL_PROTOCOL") == "HTTP" { - return newHttpServer(parallelTotal, reporter) - } else { - return newRPCServer(parallelTotal, reporter) - } -} - -func NewClient(serverHost string) Client { - if os.Getenv("GINKGO_PARALLEL_PROTOCOL") == "HTTP" { - return newHttpClient(serverHost) - } else { - return newRPCClient(serverHost) - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go deleted file mode 100644 index 6547c7a66e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go +++ /dev/null @@ -1,169 +0,0 @@ -package parallel_support - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "time" - - "github.com/onsi/ginkgo/v2/types" -) - -type httpClient struct { - serverHost string -} - -func newHttpClient(serverHost string) *httpClient { - return &httpClient{ - serverHost: serverHost, - } -} - -func (client *httpClient) Connect() bool { - resp, err := http.Get(client.serverHost + "/up") - if err != nil { - return false - } - resp.Body.Close() - return resp.StatusCode == http.StatusOK -} - -func (client *httpClient) Close() error { - return nil -} - -func (client *httpClient) post(path string, data interface{}) error { - var body io.Reader - if data != nil { - encoded, err := json.Marshal(data) - if err != nil { - return err - } - body = bytes.NewBuffer(encoded) - } - resp, err := http.Post(client.serverHost+path, "application/json", body) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("received unexpected status code %d", resp.StatusCode) - } - return nil -} - -func (client *httpClient) poll(path string, data interface{}) error { - for { - resp, err := http.Get(client.serverHost + path) - if err != nil { - return err - } - if resp.StatusCode == http.StatusTooEarly { - resp.Body.Close() - time.Sleep(POLLING_INTERVAL) - continue - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusGone { - return ErrorGone - } - if resp.StatusCode == http.StatusFailedDependency { - return ErrorFailed - } - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("received unexpected status code %d", resp.StatusCode) - } - if data != nil { - return json.NewDecoder(resp.Body).Decode(data) - } - return nil - } -} - -func (client *httpClient) PostSuiteWillBegin(report types.Report) error { - return client.post("/suite-will-begin", report) -} - -func (client *httpClient) PostDidRun(report types.SpecReport) error { - return client.post("/did-run", report) -} - -func (client *httpClient) PostSuiteDidEnd(report types.Report) error { - return client.post("/suite-did-end", report) -} - -func (client *httpClient) PostEmitProgressReport(report types.ProgressReport) error { - return client.post("/progress-report", report) -} - -func (client *httpClient) PostReportBeforeSuiteCompleted(state types.SpecState) error { - return client.post("/report-before-suite-completed", state) -} - -func (client *httpClient) BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) { - var state types.SpecState - err := client.poll("/report-before-suite-state", &state) - if err == ErrorGone { - return types.SpecStateFailed, nil - } - return state, err -} - -func (client *httpClient) PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error { - beforeSuiteState := BeforeSuiteState{ - State: state, - Data: data, - } - return client.post("/before-suite-completed", beforeSuiteState) -} - -func (client *httpClient) BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) { - var beforeSuiteState BeforeSuiteState - err := client.poll("/before-suite-state", &beforeSuiteState) - if err == ErrorGone { - return types.SpecStateInvalid, nil, types.GinkgoErrors.SynchronizedBeforeSuiteDisappearedOnProc1() - } - return beforeSuiteState.State, beforeSuiteState.Data, err -} - -func (client *httpClient) BlockUntilNonprimaryProcsHaveFinished() error { - return client.poll("/have-nonprimary-procs-finished", nil) -} - -func (client *httpClient) BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) { - var report types.Report - err := client.poll("/aggregated-nonprimary-procs-report", &report) - if err == ErrorGone { - return types.Report{}, types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing() - } - return report, err -} - -func (client *httpClient) FetchNextCounter() (int, error) { - var counter ParallelIndexCounter - err := client.poll("/counter", &counter) - return counter.Index, err -} - -func (client *httpClient) PostAbort() error { - return client.post("/abort", nil) -} - -func (client *httpClient) ShouldAbort() bool { - err := client.poll("/abort", nil) - if err == ErrorGone { - return true - } - return false -} - -func (client *httpClient) Write(p []byte) (int, error) { - resp, err := http.Post(client.serverHost+"/emit-output", "text/plain;charset=UTF-8 ", bytes.NewReader(p)) - resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return 0, fmt.Errorf("failed to emit output") - } - return len(p), err -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go deleted file mode 100644 index d2c71ab1b2..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go +++ /dev/null @@ -1,242 +0,0 @@ -/* - -The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners. -This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser). - -*/ - -package parallel_support - -import ( - "encoding/json" - "io" - "net" - "net/http" - - "github.com/onsi/ginkgo/v2/reporters" - "github.com/onsi/ginkgo/v2/types" -) - -/* -httpServer spins up on an automatically selected port and listens for communication from the forwarding reporter. -It then forwards that communication to attached reporters. -*/ -type httpServer struct { - listener net.Listener - handler *ServerHandler -} - -// Create a new server, automatically selecting a port -func newHttpServer(parallelTotal int, reporter reporters.Reporter) (*httpServer, error) { - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return nil, err - } - return &httpServer{ - listener: listener, - handler: newServerHandler(parallelTotal, reporter), - }, nil -} - -// Start the server. You don't need to `go s.Start()`, just `s.Start()` -func (server *httpServer) Start() { - httpServer := &http.Server{} - mux := http.NewServeMux() - httpServer.Handler = mux - - //streaming endpoints - mux.HandleFunc("/suite-will-begin", server.specSuiteWillBegin) - mux.HandleFunc("/did-run", server.didRun) - mux.HandleFunc("/suite-did-end", server.specSuiteDidEnd) - mux.HandleFunc("/emit-output", server.emitOutput) - mux.HandleFunc("/progress-report", server.emitProgressReport) - - //synchronization endpoints - mux.HandleFunc("/report-before-suite-completed", server.handleReportBeforeSuiteCompleted) - mux.HandleFunc("/report-before-suite-state", server.handleReportBeforeSuiteState) - mux.HandleFunc("/before-suite-completed", server.handleBeforeSuiteCompleted) - mux.HandleFunc("/before-suite-state", server.handleBeforeSuiteState) - mux.HandleFunc("/have-nonprimary-procs-finished", server.handleHaveNonprimaryProcsFinished) - mux.HandleFunc("/aggregated-nonprimary-procs-report", server.handleAggregatedNonprimaryProcsReport) - mux.HandleFunc("/counter", server.handleCounter) - mux.HandleFunc("/up", server.handleUp) - mux.HandleFunc("/abort", server.handleAbort) - - go httpServer.Serve(server.listener) -} - -// Stop the server -func (server *httpServer) Close() { - server.listener.Close() -} - -// The address the server can be reached it. Pass this into the `ForwardingReporter`. -func (server *httpServer) Address() string { - return "http://" + server.listener.Addr().String() -} - -func (server *httpServer) GetSuiteDone() chan interface{} { - return server.handler.done -} - -func (server *httpServer) GetOutputDestination() io.Writer { - return server.handler.outputDestination -} - -func (server *httpServer) SetOutputDestination(w io.Writer) { - server.handler.outputDestination = w -} - -func (server *httpServer) RegisterAlive(node int, alive func() bool) { - server.handler.registerAlive(node, alive) -} - -// -// Streaming Endpoints -// - -// The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters` -func (server *httpServer) decode(writer http.ResponseWriter, request *http.Request, object interface{}) bool { - defer request.Body.Close() - if json.NewDecoder(request.Body).Decode(object) != nil { - writer.WriteHeader(http.StatusBadRequest) - return false - } - return true -} - -func (server *httpServer) handleError(err error, writer http.ResponseWriter) bool { - if err == nil { - return false - } - switch err { - case ErrorEarly: - writer.WriteHeader(http.StatusTooEarly) - case ErrorGone: - writer.WriteHeader(http.StatusGone) - case ErrorFailed: - writer.WriteHeader(http.StatusFailedDependency) - default: - writer.WriteHeader(http.StatusInternalServerError) - } - return true -} - -func (server *httpServer) specSuiteWillBegin(writer http.ResponseWriter, request *http.Request) { - var report types.Report - if !server.decode(writer, request, &report) { - return - } - - server.handleError(server.handler.SpecSuiteWillBegin(report, voidReceiver), writer) -} - -func (server *httpServer) didRun(writer http.ResponseWriter, request *http.Request) { - var report types.SpecReport - if !server.decode(writer, request, &report) { - return - } - - server.handleError(server.handler.DidRun(report, voidReceiver), writer) -} - -func (server *httpServer) specSuiteDidEnd(writer http.ResponseWriter, request *http.Request) { - var report types.Report - if !server.decode(writer, request, &report) { - return - } - server.handleError(server.handler.SpecSuiteDidEnd(report, voidReceiver), writer) -} - -func (server *httpServer) emitOutput(writer http.ResponseWriter, request *http.Request) { - output, err := io.ReadAll(request.Body) - if err != nil { - writer.WriteHeader(http.StatusInternalServerError) - return - } - var n int - server.handleError(server.handler.EmitOutput(output, &n), writer) -} - -func (server *httpServer) emitProgressReport(writer http.ResponseWriter, request *http.Request) { - var report types.ProgressReport - if !server.decode(writer, request, &report) { - return - } - server.handleError(server.handler.EmitProgressReport(report, voidReceiver), writer) -} - -func (server *httpServer) handleReportBeforeSuiteCompleted(writer http.ResponseWriter, request *http.Request) { - var state types.SpecState - if !server.decode(writer, request, &state) { - return - } - - server.handleError(server.handler.ReportBeforeSuiteCompleted(state, voidReceiver), writer) -} - -func (server *httpServer) handleReportBeforeSuiteState(writer http.ResponseWriter, request *http.Request) { - var state types.SpecState - if server.handleError(server.handler.ReportBeforeSuiteState(voidSender, &state), writer) { - return - } - json.NewEncoder(writer).Encode(state) -} - -func (server *httpServer) handleBeforeSuiteCompleted(writer http.ResponseWriter, request *http.Request) { - var beforeSuiteState BeforeSuiteState - if !server.decode(writer, request, &beforeSuiteState) { - return - } - - server.handleError(server.handler.BeforeSuiteCompleted(beforeSuiteState, voidReceiver), writer) -} - -func (server *httpServer) handleBeforeSuiteState(writer http.ResponseWriter, request *http.Request) { - var beforeSuiteState BeforeSuiteState - if server.handleError(server.handler.BeforeSuiteState(voidSender, &beforeSuiteState), writer) { - return - } - json.NewEncoder(writer).Encode(beforeSuiteState) -} - -func (server *httpServer) handleHaveNonprimaryProcsFinished(writer http.ResponseWriter, request *http.Request) { - if server.handleError(server.handler.HaveNonprimaryProcsFinished(voidSender, voidReceiver), writer) { - return - } - writer.WriteHeader(http.StatusOK) -} - -func (server *httpServer) handleAggregatedNonprimaryProcsReport(writer http.ResponseWriter, request *http.Request) { - var aggregatedReport types.Report - if server.handleError(server.handler.AggregatedNonprimaryProcsReport(voidSender, &aggregatedReport), writer) { - return - } - json.NewEncoder(writer).Encode(aggregatedReport) -} - -func (server *httpServer) handleCounter(writer http.ResponseWriter, request *http.Request) { - var n int - if server.handleError(server.handler.Counter(voidSender, &n), writer) { - return - } - json.NewEncoder(writer).Encode(ParallelIndexCounter{Index: n}) -} - -func (server *httpServer) handleUp(writer http.ResponseWriter, request *http.Request) { - writer.WriteHeader(http.StatusOK) -} - -func (server *httpServer) handleAbort(writer http.ResponseWriter, request *http.Request) { - if request.Method == "GET" { - var shouldAbort bool - server.handler.ShouldAbort(voidSender, &shouldAbort) - if shouldAbort { - writer.WriteHeader(http.StatusGone) - } else { - writer.WriteHeader(http.StatusOK) - } - } else { - server.handler.Abort(voidSender, voidReceiver) - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go deleted file mode 100644 index 59e8e6fd0a..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go +++ /dev/null @@ -1,136 +0,0 @@ -package parallel_support - -import ( - "net/rpc" - "time" - - "github.com/onsi/ginkgo/v2/types" -) - -type rpcClient struct { - serverHost string - client *rpc.Client -} - -func newRPCClient(serverHost string) *rpcClient { - return &rpcClient{ - serverHost: serverHost, - } -} - -func (client *rpcClient) Connect() bool { - var err error - if client.client != nil { - return true - } - client.client, err = rpc.DialHTTPPath("tcp", client.serverHost, "/") - if err != nil { - client.client = nil - return false - } - return true -} - -func (client *rpcClient) Close() error { - return client.client.Close() -} - -func (client *rpcClient) poll(method string, data interface{}) error { - for { - err := client.client.Call(method, voidSender, data) - if err == nil { - return nil - } - switch err.Error() { - case ErrorEarly.Error(): - time.Sleep(POLLING_INTERVAL) - case ErrorGone.Error(): - return ErrorGone - case ErrorFailed.Error(): - return ErrorFailed - default: - return err - } - } -} - -func (client *rpcClient) PostSuiteWillBegin(report types.Report) error { - return client.client.Call("Server.SpecSuiteWillBegin", report, voidReceiver) -} - -func (client *rpcClient) PostDidRun(report types.SpecReport) error { - return client.client.Call("Server.DidRun", report, voidReceiver) -} - -func (client *rpcClient) PostSuiteDidEnd(report types.Report) error { - return client.client.Call("Server.SpecSuiteDidEnd", report, voidReceiver) -} - -func (client *rpcClient) Write(p []byte) (int, error) { - var n int - err := client.client.Call("Server.EmitOutput", p, &n) - return n, err -} - -func (client *rpcClient) PostEmitProgressReport(report types.ProgressReport) error { - return client.client.Call("Server.EmitProgressReport", report, voidReceiver) -} - -func (client *rpcClient) PostReportBeforeSuiteCompleted(state types.SpecState) error { - return client.client.Call("Server.ReportBeforeSuiteCompleted", state, voidReceiver) -} - -func (client *rpcClient) BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) { - var state types.SpecState - err := client.poll("Server.ReportBeforeSuiteState", &state) - if err == ErrorGone { - return types.SpecStateFailed, nil - } - return state, err -} - -func (client *rpcClient) PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error { - beforeSuiteState := BeforeSuiteState{ - State: state, - Data: data, - } - return client.client.Call("Server.BeforeSuiteCompleted", beforeSuiteState, voidReceiver) -} - -func (client *rpcClient) BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) { - var beforeSuiteState BeforeSuiteState - err := client.poll("Server.BeforeSuiteState", &beforeSuiteState) - if err == ErrorGone { - return types.SpecStateInvalid, nil, types.GinkgoErrors.SynchronizedBeforeSuiteDisappearedOnProc1() - } - return beforeSuiteState.State, beforeSuiteState.Data, err -} - -func (client *rpcClient) BlockUntilNonprimaryProcsHaveFinished() error { - return client.poll("Server.HaveNonprimaryProcsFinished", voidReceiver) -} - -func (client *rpcClient) BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) { - var report types.Report - err := client.poll("Server.AggregatedNonprimaryProcsReport", &report) - if err == ErrorGone { - return types.Report{}, types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing() - } - return report, err -} - -func (client *rpcClient) FetchNextCounter() (int, error) { - var counter int - err := client.client.Call("Server.Counter", voidSender, &counter) - return counter, err -} - -func (client *rpcClient) PostAbort() error { - return client.client.Call("Server.Abort", voidSender, voidReceiver) -} - -func (client *rpcClient) ShouldAbort() bool { - var shouldAbort bool - client.client.Call("Server.ShouldAbort", voidSender, &shouldAbort) - return shouldAbort -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go deleted file mode 100644 index 2620fd562d..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go +++ /dev/null @@ -1,75 +0,0 @@ -/* - -The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners. -This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser). - -*/ - -package parallel_support - -import ( - "io" - "net" - "net/http" - "net/rpc" - - "github.com/onsi/ginkgo/v2/reporters" -) - -/* -RPCServer spins up on an automatically selected port and listens for communication from the forwarding reporter. -It then forwards that communication to attached reporters. -*/ -type RPCServer struct { - listener net.Listener - handler *ServerHandler -} - -//Create a new server, automatically selecting a port -func newRPCServer(parallelTotal int, reporter reporters.Reporter) (*RPCServer, error) { - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return nil, err - } - return &RPCServer{ - listener: listener, - handler: newServerHandler(parallelTotal, reporter), - }, nil -} - -//Start the server. You don't need to `go s.Start()`, just `s.Start()` -func (server *RPCServer) Start() { - rpcServer := rpc.NewServer() - rpcServer.RegisterName("Server", server.handler) //register the handler's methods as the server - - httpServer := &http.Server{} - httpServer.Handler = rpcServer - - go httpServer.Serve(server.listener) -} - -//Stop the server -func (server *RPCServer) Close() { - server.listener.Close() -} - -//The address the server can be reached it. Pass this into the `ForwardingReporter`. -func (server *RPCServer) Address() string { - return server.listener.Addr().String() -} - -func (server *RPCServer) GetSuiteDone() chan interface{} { - return server.handler.done -} - -func (server *RPCServer) GetOutputDestination() io.Writer { - return server.handler.outputDestination -} - -func (server *RPCServer) SetOutputDestination(w io.Writer) { - server.handler.outputDestination = w -} - -func (server *RPCServer) RegisterAlive(node int, alive func() bool) { - server.handler.registerAlive(node, alive) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go deleted file mode 100644 index a6d98793e9..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go +++ /dev/null @@ -1,234 +0,0 @@ -package parallel_support - -import ( - "io" - "os" - "sync" - - "github.com/onsi/ginkgo/v2/reporters" - "github.com/onsi/ginkgo/v2/types" -) - -type Void struct{} - -var voidReceiver *Void = &Void{} -var voidSender Void - -// ServerHandler is an RPC-compatible handler that is shared between the http server and the rpc server. -// It handles all the business logic to avoid duplication between the two servers - -type ServerHandler struct { - done chan interface{} - outputDestination io.Writer - reporter reporters.Reporter - alives []func() bool - lock *sync.Mutex - beforeSuiteState BeforeSuiteState - reportBeforeSuiteState types.SpecState - parallelTotal int - counter int - counterLock *sync.Mutex - shouldAbort bool - - numSuiteDidBegins int - numSuiteDidEnds int - aggregatedReport types.Report - reportHoldingArea []types.SpecReport -} - -func newServerHandler(parallelTotal int, reporter reporters.Reporter) *ServerHandler { - return &ServerHandler{ - reporter: reporter, - lock: &sync.Mutex{}, - counterLock: &sync.Mutex{}, - alives: make([]func() bool, parallelTotal), - beforeSuiteState: BeforeSuiteState{Data: nil, State: types.SpecStateInvalid}, - - parallelTotal: parallelTotal, - outputDestination: os.Stdout, - done: make(chan interface{}), - } -} - -func (handler *ServerHandler) SpecSuiteWillBegin(report types.Report, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - - handler.numSuiteDidBegins += 1 - - // all summaries are identical, so it's fine to simply emit the last one of these - if handler.numSuiteDidBegins == handler.parallelTotal { - handler.reporter.SuiteWillBegin(report) - - for _, summary := range handler.reportHoldingArea { - handler.reporter.WillRun(summary) - handler.reporter.DidRun(summary) - } - - handler.reportHoldingArea = nil - } - - return nil -} - -func (handler *ServerHandler) DidRun(report types.SpecReport, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - - if handler.numSuiteDidBegins == handler.parallelTotal { - handler.reporter.WillRun(report) - handler.reporter.DidRun(report) - } else { - handler.reportHoldingArea = append(handler.reportHoldingArea, report) - } - - return nil -} - -func (handler *ServerHandler) SpecSuiteDidEnd(report types.Report, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - - handler.numSuiteDidEnds += 1 - if handler.numSuiteDidEnds == 1 { - handler.aggregatedReport = report - } else { - handler.aggregatedReport = handler.aggregatedReport.Add(report) - } - - if handler.numSuiteDidEnds == handler.parallelTotal { - handler.reporter.SuiteDidEnd(handler.aggregatedReport) - close(handler.done) - } - - return nil -} - -func (handler *ServerHandler) EmitOutput(output []byte, n *int) error { - var err error - *n, err = handler.outputDestination.Write(output) - return err -} - -func (handler *ServerHandler) EmitProgressReport(report types.ProgressReport, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - handler.reporter.EmitProgressReport(report) - return nil -} - -func (handler *ServerHandler) registerAlive(proc int, alive func() bool) { - handler.lock.Lock() - defer handler.lock.Unlock() - handler.alives[proc-1] = alive -} - -func (handler *ServerHandler) procIsAlive(proc int) bool { - handler.lock.Lock() - defer handler.lock.Unlock() - alive := handler.alives[proc-1] - if alive == nil { - return true - } - return alive() -} - -func (handler *ServerHandler) haveNonprimaryProcsFinished() bool { - for i := 2; i <= handler.parallelTotal; i++ { - if handler.procIsAlive(i) { - return false - } - } - return true -} - -func (handler *ServerHandler) ReportBeforeSuiteCompleted(reportBeforeSuiteState types.SpecState, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - handler.reportBeforeSuiteState = reportBeforeSuiteState - - return nil -} - -func (handler *ServerHandler) ReportBeforeSuiteState(_ Void, reportBeforeSuiteState *types.SpecState) error { - proc1IsAlive := handler.procIsAlive(1) - handler.lock.Lock() - defer handler.lock.Unlock() - if handler.reportBeforeSuiteState == types.SpecStateInvalid { - if proc1IsAlive { - return ErrorEarly - } else { - return ErrorGone - } - } - *reportBeforeSuiteState = handler.reportBeforeSuiteState - return nil -} - -func (handler *ServerHandler) BeforeSuiteCompleted(beforeSuiteState BeforeSuiteState, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - handler.beforeSuiteState = beforeSuiteState - - return nil -} - -func (handler *ServerHandler) BeforeSuiteState(_ Void, beforeSuiteState *BeforeSuiteState) error { - proc1IsAlive := handler.procIsAlive(1) - handler.lock.Lock() - defer handler.lock.Unlock() - if handler.beforeSuiteState.State == types.SpecStateInvalid { - if proc1IsAlive { - return ErrorEarly - } else { - return ErrorGone - } - } - *beforeSuiteState = handler.beforeSuiteState - return nil -} - -func (handler *ServerHandler) HaveNonprimaryProcsFinished(_ Void, _ *Void) error { - if handler.haveNonprimaryProcsFinished() { - return nil - } else { - return ErrorEarly - } -} - -func (handler *ServerHandler) AggregatedNonprimaryProcsReport(_ Void, report *types.Report) error { - if handler.haveNonprimaryProcsFinished() { - handler.lock.Lock() - defer handler.lock.Unlock() - if handler.numSuiteDidEnds == handler.parallelTotal-1 { - *report = handler.aggregatedReport - return nil - } else { - return ErrorGone - } - } else { - return ErrorEarly - } -} - -func (handler *ServerHandler) Counter(_ Void, counter *int) error { - handler.counterLock.Lock() - defer handler.counterLock.Unlock() - *counter = handler.counter - handler.counter++ - return nil -} - -func (handler *ServerHandler) Abort(_ Void, _ *Void) error { - handler.lock.Lock() - defer handler.lock.Unlock() - handler.shouldAbort = true - return nil -} - -func (handler *ServerHandler) ShouldAbort(_ Void, shouldAbort *bool) error { - handler.lock.Lock() - defer handler.lock.Unlock() - *shouldAbort = handler.shouldAbort - return nil -} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go deleted file mode 100644 index 56b7be7587..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go +++ /dev/null @@ -1,759 +0,0 @@ -/* -Ginkgo's Default Reporter - -A number of command line flags are available to tweak Ginkgo's default output. - -These are documented [here](http://onsi.github.io/ginkgo/#running_tests) -*/ -package reporters - -import ( - "fmt" - "io" - "runtime" - "strings" - "sync" - "time" - - "github.com/onsi/ginkgo/v2/formatter" - "github.com/onsi/ginkgo/v2/types" -) - -type DefaultReporter struct { - conf types.ReporterConfig - writer io.Writer - - // managing the emission stream - lastCharWasNewline bool - lastEmissionWasDelimiter bool - - // rendering - specDenoter string - retryDenoter string - formatter formatter.Formatter - - runningInParallel bool - lock *sync.Mutex -} - -func NewDefaultReporterUnderTest(conf types.ReporterConfig, writer io.Writer) *DefaultReporter { - reporter := NewDefaultReporter(conf, writer) - reporter.formatter = formatter.New(formatter.ColorModePassthrough) - - return reporter -} - -func NewDefaultReporter(conf types.ReporterConfig, writer io.Writer) *DefaultReporter { - reporter := &DefaultReporter{ - conf: conf, - writer: writer, - - lastCharWasNewline: true, - lastEmissionWasDelimiter: false, - - specDenoter: "•", - retryDenoter: "↺", - formatter: formatter.NewWithNoColorBool(conf.NoColor), - lock: &sync.Mutex{}, - } - if runtime.GOOS == "windows" { - reporter.specDenoter = "+" - reporter.retryDenoter = "R" - } - - return reporter -} - -/* The Reporter Interface */ - -func (r *DefaultReporter) SuiteWillBegin(report types.Report) { - if r.conf.Verbosity().Is(types.VerbosityLevelSuccinct) { - r.emit(r.f("[%d] {{bold}}%s{{/}} ", report.SuiteConfig.RandomSeed, report.SuiteDescription)) - if len(report.SuiteLabels) > 0 { - r.emit(r.f("{{coral}}[%s]{{/}} ", strings.Join(report.SuiteLabels, ", "))) - } - r.emit(r.f("- %d/%d specs ", report.PreRunStats.SpecsThatWillRun, report.PreRunStats.TotalSpecs)) - if report.SuiteConfig.ParallelTotal > 1 { - r.emit(r.f("- %d procs ", report.SuiteConfig.ParallelTotal)) - } - } else { - banner := r.f("Running Suite: %s - %s", report.SuiteDescription, report.SuitePath) - r.emitBlock(banner) - bannerWidth := len(banner) - if len(report.SuiteLabels) > 0 { - labels := strings.Join(report.SuiteLabels, ", ") - r.emitBlock(r.f("{{coral}}[%s]{{/}} ", labels)) - if len(labels)+2 > bannerWidth { - bannerWidth = len(labels) + 2 - } - } - r.emitBlock(strings.Repeat("=", bannerWidth)) - - out := r.f("Random Seed: {{bold}}%d{{/}}", report.SuiteConfig.RandomSeed) - if report.SuiteConfig.RandomizeAllSpecs { - out += r.f(" - will randomize all specs") - } - r.emitBlock(out) - r.emit("\n") - r.emitBlock(r.f("Will run {{bold}}%d{{/}} of {{bold}}%d{{/}} specs", report.PreRunStats.SpecsThatWillRun, report.PreRunStats.TotalSpecs)) - if report.SuiteConfig.ParallelTotal > 1 { - r.emitBlock(r.f("Running in parallel across {{bold}}%d{{/}} processes", report.SuiteConfig.ParallelTotal)) - } - } -} - -func (r *DefaultReporter) SuiteDidEnd(report types.Report) { - failures := report.SpecReports.WithState(types.SpecStateFailureStates) - if len(failures) > 0 { - r.emitBlock("\n") - if len(failures) > 1 { - r.emitBlock(r.f("{{red}}{{bold}}Summarizing %d Failures:{{/}}", len(failures))) - } else { - r.emitBlock(r.f("{{red}}{{bold}}Summarizing 1 Failure:{{/}}")) - } - for _, specReport := range failures { - highlightColor, heading := "{{red}}", "[FAIL]" - switch specReport.State { - case types.SpecStatePanicked: - highlightColor, heading = "{{magenta}}", "[PANICKED!]" - case types.SpecStateAborted: - highlightColor, heading = "{{coral}}", "[ABORTED]" - case types.SpecStateTimedout: - highlightColor, heading = "{{orange}}", "[TIMEDOUT]" - case types.SpecStateInterrupted: - highlightColor, heading = "{{orange}}", "[INTERRUPTED]" - } - locationBlock := r.codeLocationBlock(specReport, highlightColor, false, true) - r.emitBlock(r.fi(1, highlightColor+"%s{{/}} %s", heading, locationBlock)) - } - } - - //summarize the suite - if r.conf.Verbosity().Is(types.VerbosityLevelSuccinct) && report.SuiteSucceeded { - r.emit(r.f(" {{green}}SUCCESS!{{/}} %s ", report.RunTime)) - return - } - - r.emitBlock("\n") - color, status := "{{green}}{{bold}}", "SUCCESS!" - if !report.SuiteSucceeded { - color, status = "{{red}}{{bold}}", "FAIL!" - } - - specs := report.SpecReports.WithLeafNodeType(types.NodeTypeIt) //exclude any suite setup nodes - r.emitBlock(r.f(color+"Ran %d of %d Specs in %.3f seconds{{/}}", - specs.CountWithState(types.SpecStatePassed)+specs.CountWithState(types.SpecStateFailureStates), - report.PreRunStats.TotalSpecs, - report.RunTime.Seconds()), - ) - - switch len(report.SpecialSuiteFailureReasons) { - case 0: - r.emit(r.f(color+"%s{{/}} -- ", status)) - case 1: - r.emit(r.f(color+"%s - %s{{/}} -- ", status, report.SpecialSuiteFailureReasons[0])) - default: - r.emitBlock(r.f(color+"%s - %s{{/}}\n", status, strings.Join(report.SpecialSuiteFailureReasons, ", "))) - } - - if len(specs) == 0 && report.SpecReports.WithLeafNodeType(types.NodeTypeBeforeSuite|types.NodeTypeSynchronizedBeforeSuite).CountWithState(types.SpecStateFailureStates) > 0 { - r.emit(r.f("{{cyan}}{{bold}}A BeforeSuite node failed so all tests were skipped.{{/}}\n")) - } else { - r.emit(r.f("{{green}}{{bold}}%d Passed{{/}} | ", specs.CountWithState(types.SpecStatePassed))) - r.emit(r.f("{{red}}{{bold}}%d Failed{{/}} | ", specs.CountWithState(types.SpecStateFailureStates))) - if specs.CountOfFlakedSpecs() > 0 { - r.emit(r.f("{{light-yellow}}{{bold}}%d Flaked{{/}} | ", specs.CountOfFlakedSpecs())) - } - if specs.CountOfRepeatedSpecs() > 0 { - r.emit(r.f("{{light-yellow}}{{bold}}%d Repeated{{/}} | ", specs.CountOfRepeatedSpecs())) - } - r.emit(r.f("{{yellow}}{{bold}}%d Pending{{/}} | ", specs.CountWithState(types.SpecStatePending))) - r.emit(r.f("{{cyan}}{{bold}}%d Skipped{{/}}\n", specs.CountWithState(types.SpecStateSkipped))) - } -} - -func (r *DefaultReporter) WillRun(report types.SpecReport) { - v := r.conf.Verbosity() - if v.LT(types.VerbosityLevelVerbose) || report.State.Is(types.SpecStatePending|types.SpecStateSkipped) || report.RunningInParallel { - return - } - - r.emitDelimiter(0) - r.emitBlock(r.f(r.codeLocationBlock(report, "{{/}}", v.Is(types.VerbosityLevelVeryVerbose), false))) -} - -func (r *DefaultReporter) DidRun(report types.SpecReport) { - v := r.conf.Verbosity() - inParallel := report.RunningInParallel - - header := r.specDenoter - if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { - header = fmt.Sprintf("[%s]", report.LeafNodeType) - } - highlightColor := r.highlightColorForState(report.State) - - // have we already been streaming the timeline? - timelineHasBeenStreaming := v.GTE(types.VerbosityLevelVerbose) && !inParallel - - // should we show the timeline? - var timeline types.Timeline - showTimeline := !timelineHasBeenStreaming && (v.GTE(types.VerbosityLevelVerbose) || report.Failed()) - if showTimeline { - timeline = report.Timeline().WithoutHiddenReportEntries() - keepVeryVerboseSpecEvents := v.Is(types.VerbosityLevelVeryVerbose) || - (v.Is(types.VerbosityLevelVerbose) && r.conf.ShowNodeEvents) || - (report.Failed() && r.conf.ShowNodeEvents) - if !keepVeryVerboseSpecEvents { - timeline = timeline.WithoutVeryVerboseSpecEvents() - } - if len(timeline) == 0 && report.CapturedGinkgoWriterOutput == "" { - // the timeline is completely empty - don't show it - showTimeline = false - } - if v.LT(types.VerbosityLevelVeryVerbose) && report.CapturedGinkgoWriterOutput == "" && len(timeline) > 0 { - //if we aren't -vv and the timeline only has a single failure, don't show it as it will appear at the end of the report - failure, isFailure := timeline[0].(types.Failure) - if isFailure && (len(timeline) == 1 || (len(timeline) == 2 && failure.AdditionalFailure != nil)) { - showTimeline = false - } - } - } - - // should we have a separate section for always-visible reports? - showSeparateVisibilityAlwaysReportsSection := !timelineHasBeenStreaming && !showTimeline && report.ReportEntries.HasVisibility(types.ReportEntryVisibilityAlways) - - // should we have a separate section for captured stdout/stderr - showSeparateStdSection := inParallel && (report.CapturedStdOutErr != "") - - // given all that - do we have any actual content to show? or are we a single denoter in a stream? - reportHasContent := v.Is(types.VerbosityLevelVeryVerbose) || showTimeline || showSeparateVisibilityAlwaysReportsSection || showSeparateStdSection || report.Failed() || (v.Is(types.VerbosityLevelVerbose) && !report.State.Is(types.SpecStateSkipped)) - - // should we show a runtime? - includeRuntime := !report.State.Is(types.SpecStateSkipped|types.SpecStatePending) || (report.State.Is(types.SpecStateSkipped) && report.Failure.Message != "") - - // should we show the codelocation block? - showCodeLocation := !timelineHasBeenStreaming || !report.State.Is(types.SpecStatePassed) - - switch report.State { - case types.SpecStatePassed: - if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) && !reportHasContent { - return - } - if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { - header = fmt.Sprintf("%s PASSED", header) - } - if report.NumAttempts > 1 && report.MaxFlakeAttempts > 1 { - header, reportHasContent = fmt.Sprintf("%s [FLAKEY TEST - TOOK %d ATTEMPTS TO PASS]", r.retryDenoter, report.NumAttempts), true - } - case types.SpecStatePending: - header = "P" - if v.GT(types.VerbosityLevelSuccinct) { - header, reportHasContent = "P [PENDING]", true - } - case types.SpecStateSkipped: - header = "S" - if v.Is(types.VerbosityLevelVeryVerbose) || (v.Is(types.VerbosityLevelVerbose) && report.Failure.Message != "") { - header, reportHasContent = "S [SKIPPED]", true - } - default: - header = fmt.Sprintf("%s [%s]", header, r.humanReadableState(report.State)) - if report.MaxMustPassRepeatedly > 1 { - header = fmt.Sprintf("%s DURING REPETITION #%d", header, report.NumAttempts) - } - } - - // If we have no content to show, jsut emit the header and return - if !reportHasContent { - r.emit(r.f(highlightColor + header + "{{/}}")) - return - } - - if includeRuntime { - header = r.f("%s [%.3f seconds]", header, report.RunTime.Seconds()) - } - - // Emit header - if !timelineHasBeenStreaming { - r.emitDelimiter(0) - } - r.emitBlock(r.f(highlightColor + header + "{{/}}")) - if showCodeLocation { - r.emitBlock(r.codeLocationBlock(report, highlightColor, v.Is(types.VerbosityLevelVeryVerbose), false)) - } - - //Emit Stdout/Stderr Output - if showSeparateStdSection { - r.emitBlock("\n") - r.emitBlock(r.fi(1, "{{gray}}Captured StdOut/StdErr Output >>{{/}}")) - r.emitBlock(r.fi(1, "%s", report.CapturedStdOutErr)) - r.emitBlock(r.fi(1, "{{gray}}<< Captured StdOut/StdErr Output{{/}}")) - } - - if showSeparateVisibilityAlwaysReportsSection { - r.emitBlock("\n") - r.emitBlock(r.fi(1, "{{gray}}Report Entries >>{{/}}")) - for _, entry := range report.ReportEntries.WithVisibility(types.ReportEntryVisibilityAlways) { - r.emitReportEntry(1, entry) - } - r.emitBlock(r.fi(1, "{{gray}}<< Report Entries{{/}}")) - } - - if showTimeline { - r.emitBlock("\n") - r.emitBlock(r.fi(1, "{{gray}}Timeline >>{{/}}")) - r.emitTimeline(1, report, timeline) - r.emitBlock(r.fi(1, "{{gray}}<< Timeline{{/}}")) - } - - // Emit Failure Message - if !report.Failure.IsZero() && !v.Is(types.VerbosityLevelVeryVerbose) { - r.emitBlock("\n") - r.emitFailure(1, report.State, report.Failure, true) - if len(report.AdditionalFailures) > 0 { - r.emitBlock(r.fi(1, "\nThere were {{bold}}{{red}}additional failures{{/}} detected. To view them in detail run {{bold}}ginkgo -vv{{/}}")) - } - } - - r.emitDelimiter(0) -} - -func (r *DefaultReporter) highlightColorForState(state types.SpecState) string { - switch state { - case types.SpecStatePassed: - return "{{green}}" - case types.SpecStatePending: - return "{{yellow}}" - case types.SpecStateSkipped: - return "{{cyan}}" - case types.SpecStateFailed: - return "{{red}}" - case types.SpecStateTimedout: - return "{{orange}}" - case types.SpecStatePanicked: - return "{{magenta}}" - case types.SpecStateInterrupted: - return "{{orange}}" - case types.SpecStateAborted: - return "{{coral}}" - default: - return "{{gray}}" - } -} - -func (r *DefaultReporter) humanReadableState(state types.SpecState) string { - return strings.ToUpper(state.String()) -} - -func (r *DefaultReporter) emitTimeline(indent uint, report types.SpecReport, timeline types.Timeline) { - isVeryVerbose := r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose) - gw := report.CapturedGinkgoWriterOutput - cursor := 0 - for _, entry := range timeline { - tl := entry.GetTimelineLocation() - if tl.Offset < len(gw) { - r.emit(r.fi(indent, "%s", gw[cursor:tl.Offset])) - cursor = tl.Offset - } else if cursor < len(gw) { - r.emit(r.fi(indent, "%s", gw[cursor:])) - cursor = len(gw) - } - switch x := entry.(type) { - case types.Failure: - if isVeryVerbose { - r.emitFailure(indent, report.State, x, false) - } else { - r.emitShortFailure(indent, report.State, x) - } - case types.AdditionalFailure: - if isVeryVerbose { - r.emitFailure(indent, x.State, x.Failure, true) - } else { - r.emitShortFailure(indent, x.State, x.Failure) - } - case types.ReportEntry: - r.emitReportEntry(indent, x) - case types.ProgressReport: - r.emitProgressReport(indent, false, x) - case types.SpecEvent: - if isVeryVerbose || !x.IsOnlyVisibleAtVeryVerbose() || r.conf.ShowNodeEvents { - r.emitSpecEvent(indent, x, isVeryVerbose) - } - } - } - if cursor < len(gw) { - r.emit(r.fi(indent, "%s", gw[cursor:])) - } -} - -func (r *DefaultReporter) EmitFailure(state types.SpecState, failure types.Failure) { - if r.conf.Verbosity().Is(types.VerbosityLevelVerbose) { - r.emitShortFailure(1, state, failure) - } else if r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose) { - r.emitFailure(1, state, failure, true) - } -} - -func (r *DefaultReporter) emitShortFailure(indent uint, state types.SpecState, failure types.Failure) { - r.emitBlock(r.fi(indent, r.highlightColorForState(state)+"[%s]{{/}} in [%s] - %s {{gray}}@ %s{{/}}", - r.humanReadableState(state), - failure.FailureNodeType, - failure.Location, - failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), - )) -} - -func (r *DefaultReporter) emitFailure(indent uint, state types.SpecState, failure types.Failure, includeAdditionalFailure bool) { - highlightColor := r.highlightColorForState(state) - r.emitBlock(r.fi(indent, highlightColor+"[%s] %s{{/}}", r.humanReadableState(state), failure.Message)) - r.emitBlock(r.fi(indent, highlightColor+"In {{bold}}[%s]{{/}}"+highlightColor+" at: {{bold}}%s{{/}} {{gray}}@ %s{{/}}\n", failure.FailureNodeType, failure.Location, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) - if failure.ForwardedPanic != "" { - r.emitBlock("\n") - r.emitBlock(r.fi(indent, highlightColor+"%s{{/}}", failure.ForwardedPanic)) - } - - if r.conf.FullTrace || failure.ForwardedPanic != "" { - r.emitBlock("\n") - r.emitBlock(r.fi(indent, highlightColor+"Full Stack Trace{{/}}")) - r.emitBlock(r.fi(indent+1, "%s", failure.Location.FullStackTrace)) - } - - if !failure.ProgressReport.IsZero() { - r.emitBlock("\n") - r.emitProgressReport(indent, false, failure.ProgressReport) - } - - if failure.AdditionalFailure != nil && includeAdditionalFailure { - r.emitBlock("\n") - r.emitFailure(indent, failure.AdditionalFailure.State, failure.AdditionalFailure.Failure, true) - } -} - -func (r *DefaultReporter) EmitProgressReport(report types.ProgressReport) { - r.emitDelimiter(1) - - if report.RunningInParallel { - r.emit(r.fi(1, "{{coral}}Progress Report for Ginkgo Process #{{bold}}%d{{/}}\n", report.ParallelProcess)) - } - shouldEmitGW := report.RunningInParallel || r.conf.Verbosity().LT(types.VerbosityLevelVerbose) - r.emitProgressReport(1, shouldEmitGW, report) - r.emitDelimiter(1) -} - -func (r *DefaultReporter) emitProgressReport(indent uint, emitGinkgoWriterOutput bool, report types.ProgressReport) { - if report.Message != "" { - r.emitBlock(r.fi(indent, report.Message+"\n")) - indent += 1 - } - if report.LeafNodeText != "" { - subjectIndent := indent - if len(report.ContainerHierarchyTexts) > 0 { - r.emit(r.fi(indent, r.cycleJoin(report.ContainerHierarchyTexts, " "))) - r.emit(" ") - subjectIndent = 0 - } - r.emit(r.fi(subjectIndent, "{{bold}}{{orange}}%s{{/}} (Spec Runtime: %s)\n", report.LeafNodeText, report.Time().Sub(report.SpecStartTime).Round(time.Millisecond))) - r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.LeafNodeLocation)) - indent += 1 - } - if report.CurrentNodeType != types.NodeTypeInvalid { - r.emit(r.fi(indent, "In {{bold}}{{orange}}[%s]{{/}}", report.CurrentNodeType)) - if report.CurrentNodeText != "" && !report.CurrentNodeType.Is(types.NodeTypeIt) { - r.emit(r.f(" {{bold}}{{orange}}%s{{/}}", report.CurrentNodeText)) - } - - r.emit(r.f(" (Node Runtime: %s)\n", report.Time().Sub(report.CurrentNodeStartTime).Round(time.Millisecond))) - r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.CurrentNodeLocation)) - indent += 1 - } - if report.CurrentStepText != "" { - r.emit(r.fi(indent, "At {{bold}}{{orange}}[By Step] %s{{/}} (Step Runtime: %s)\n", report.CurrentStepText, report.Time().Sub(report.CurrentStepStartTime).Round(time.Millisecond))) - r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.CurrentStepLocation)) - indent += 1 - } - - if indent > 0 { - indent -= 1 - } - - if emitGinkgoWriterOutput && report.CapturedGinkgoWriterOutput != "" { - r.emit("\n") - r.emitBlock(r.fi(indent, "{{gray}}Begin Captured GinkgoWriter Output >>{{/}}")) - limit, lines := 10, strings.Split(report.CapturedGinkgoWriterOutput, "\n") - if len(lines) <= limit { - r.emitBlock(r.fi(indent+1, "%s", report.CapturedGinkgoWriterOutput)) - } else { - r.emitBlock(r.fi(indent+1, "{{gray}}...{{/}}")) - for _, line := range lines[len(lines)-limit-1:] { - r.emitBlock(r.fi(indent+1, "%s", line)) - } - } - r.emitBlock(r.fi(indent, "{{gray}}<< End Captured GinkgoWriter Output{{/}}")) - } - - if !report.SpecGoroutine().IsZero() { - r.emit("\n") - r.emit(r.fi(indent, "{{bold}}{{underline}}Spec Goroutine{{/}}\n")) - r.emitGoroutines(indent, report.SpecGoroutine()) - } - - if len(report.AdditionalReports) > 0 { - r.emit("\n") - r.emitBlock(r.fi(indent, "{{gray}}Begin Additional Progress Reports >>{{/}}")) - for i, additionalReport := range report.AdditionalReports { - r.emit(r.fi(indent+1, additionalReport)) - if i < len(report.AdditionalReports)-1 { - r.emitBlock(r.fi(indent+1, "{{gray}}%s{{/}}", strings.Repeat("-", 10))) - } - } - r.emitBlock(r.fi(indent, "{{gray}}<< End Additional Progress Reports{{/}}")) - } - - highlightedGoroutines := report.HighlightedGoroutines() - if len(highlightedGoroutines) > 0 { - r.emit("\n") - r.emit(r.fi(indent, "{{bold}}{{underline}}Goroutines of Interest{{/}}\n")) - r.emitGoroutines(indent, highlightedGoroutines...) - } - - otherGoroutines := report.OtherGoroutines() - if len(otherGoroutines) > 0 { - r.emit("\n") - r.emit(r.fi(indent, "{{gray}}{{bold}}{{underline}}Other Goroutines{{/}}\n")) - r.emitGoroutines(indent, otherGoroutines...) - } -} - -func (r *DefaultReporter) EmitReportEntry(entry types.ReportEntry) { - if r.conf.Verbosity().LT(types.VerbosityLevelVerbose) || entry.Visibility == types.ReportEntryVisibilityNever { - return - } - r.emitReportEntry(1, entry) -} - -func (r *DefaultReporter) emitReportEntry(indent uint, entry types.ReportEntry) { - r.emitBlock(r.fi(indent, "{{bold}}"+entry.Name+"{{gray}} "+fmt.Sprintf("- %s @ %s{{/}}", entry.Location, entry.Time.Format(types.GINKGO_TIME_FORMAT)))) - if representation := entry.StringRepresentation(); representation != "" { - r.emitBlock(r.fi(indent+1, representation)) - } -} - -func (r *DefaultReporter) EmitSpecEvent(event types.SpecEvent) { - v := r.conf.Verbosity() - if v.Is(types.VerbosityLevelVeryVerbose) || (v.Is(types.VerbosityLevelVerbose) && (r.conf.ShowNodeEvents || !event.IsOnlyVisibleAtVeryVerbose())) { - r.emitSpecEvent(1, event, r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose)) - } -} - -func (r *DefaultReporter) emitSpecEvent(indent uint, event types.SpecEvent, includeLocation bool) { - location := "" - if includeLocation { - location = fmt.Sprintf("- %s ", event.CodeLocation.String()) - } - switch event.SpecEventType { - case types.SpecEventInvalid: - return - case types.SpecEventByStart: - r.emitBlock(r.fi(indent, "{{bold}}STEP:{{/}} %s {{gray}}%s@ %s{{/}}", event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) - case types.SpecEventByEnd: - r.emitBlock(r.fi(indent, "{{bold}}END STEP:{{/}} %s {{gray}}%s@ %s (%s){{/}}", event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), event.Duration.Round(time.Millisecond))) - case types.SpecEventNodeStart: - r.emitBlock(r.fi(indent, "> Enter {{bold}}[%s]{{/}} %s {{gray}}%s@ %s{{/}}", event.NodeType.String(), event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) - case types.SpecEventNodeEnd: - r.emitBlock(r.fi(indent, "< Exit {{bold}}[%s]{{/}} %s {{gray}}%s@ %s (%s){{/}}", event.NodeType.String(), event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), event.Duration.Round(time.Millisecond))) - case types.SpecEventSpecRepeat: - r.emitBlock(r.fi(indent, "\n{{bold}}Attempt #%d {{green}}Passed{{/}}{{bold}}. Repeating %s{{/}} {{gray}}@ %s{{/}}\n\n", event.Attempt, r.retryDenoter, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) - case types.SpecEventSpecRetry: - r.emitBlock(r.fi(indent, "\n{{bold}}Attempt #%d {{red}}Failed{{/}}{{bold}}. Retrying %s{{/}} {{gray}}@ %s{{/}}\n\n", event.Attempt, r.retryDenoter, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) - } -} - -func (r *DefaultReporter) emitGoroutines(indent uint, goroutines ...types.Goroutine) { - for idx, g := range goroutines { - color := "{{gray}}" - if g.HasHighlights() { - color = "{{orange}}" - } - r.emit(r.fi(indent, color+"goroutine %d [%s]{{/}}\n", g.ID, g.State)) - for _, fc := range g.Stack { - if fc.Highlight { - r.emit(r.fi(indent, color+"{{bold}}> %s{{/}}\n", fc.Function)) - r.emit(r.fi(indent+2, color+"{{bold}}%s:%d{{/}}\n", fc.Filename, fc.Line)) - r.emitSource(indent+3, fc) - } else { - r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", fc.Function)) - r.emit(r.fi(indent+2, "{{gray}}%s:%d{{/}}\n", fc.Filename, fc.Line)) - } - } - - if idx+1 < len(goroutines) { - r.emit("\n") - } - } -} - -func (r *DefaultReporter) emitSource(indent uint, fc types.FunctionCall) { - lines := fc.Source - if len(lines) == 0 { - return - } - - lTrim := 100000 - for _, line := range lines { - lTrimLine := len(line) - len(strings.TrimLeft(line, " \t")) - if lTrimLine < lTrim && len(line) > 0 { - lTrim = lTrimLine - } - } - if lTrim == 100000 { - lTrim = 0 - } - - for idx, line := range lines { - if len(line) > lTrim { - line = line[lTrim:] - } - if idx == fc.SourceHighlight { - r.emit(r.fi(indent, "{{bold}}{{orange}}> %s{{/}}\n", line)) - } else { - r.emit(r.fi(indent, "| %s\n", line)) - } - } -} - -/* Emitting to the writer */ -func (r *DefaultReporter) emit(s string) { - r._emit(s, false, false) -} - -func (r *DefaultReporter) emitBlock(s string) { - r._emit(s, true, false) -} - -func (r *DefaultReporter) emitDelimiter(indent uint) { - r._emit(r.fi(indent, "{{gray}}%s{{/}}", strings.Repeat("-", 30)), true, true) -} - -// a bit ugly - but we're trying to minimize locking on this hot codepath -func (r *DefaultReporter) _emit(s string, block bool, isDelimiter bool) { - if len(s) == 0 { - return - } - r.lock.Lock() - defer r.lock.Unlock() - if isDelimiter && r.lastEmissionWasDelimiter { - return - } - if block && !r.lastCharWasNewline { - r.writer.Write([]byte("\n")) - } - r.lastCharWasNewline = (s[len(s)-1:] == "\n") - r.writer.Write([]byte(s)) - if block && !r.lastCharWasNewline { - r.writer.Write([]byte("\n")) - r.lastCharWasNewline = true - } - r.lastEmissionWasDelimiter = isDelimiter -} - -/* Rendering text */ -func (r *DefaultReporter) f(format string, args ...interface{}) string { - return r.formatter.F(format, args...) -} - -func (r *DefaultReporter) fi(indentation uint, format string, args ...interface{}) string { - return r.formatter.Fi(indentation, format, args...) -} - -func (r *DefaultReporter) cycleJoin(elements []string, joiner string) string { - return r.formatter.CycleJoin(elements, joiner, []string{"{{/}}", "{{gray}}"}) -} - -func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightColor string, veryVerbose bool, usePreciseFailureLocation bool) string { - texts, locations, labels := []string{}, []types.CodeLocation{}, [][]string{} - texts, locations, labels = append(texts, report.ContainerHierarchyTexts...), append(locations, report.ContainerHierarchyLocations...), append(labels, report.ContainerHierarchyLabels...) - - if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { - texts = append(texts, r.f("[%s] %s", report.LeafNodeType, report.LeafNodeText)) - } else { - texts = append(texts, r.f(report.LeafNodeText)) - } - labels = append(labels, report.LeafNodeLabels) - locations = append(locations, report.LeafNodeLocation) - - failureLocation := report.Failure.FailureNodeLocation - if usePreciseFailureLocation { - failureLocation = report.Failure.Location - } - - highlightIndex := -1 - switch report.Failure.FailureNodeContext { - case types.FailureNodeAtTopLevel: - texts = append([]string{fmt.Sprintf("TOP-LEVEL [%s]", report.Failure.FailureNodeType)}, texts...) - locations = append([]types.CodeLocation{failureLocation}, locations...) - labels = append([][]string{{}}, labels...) - highlightIndex = 0 - case types.FailureNodeInContainer: - i := report.Failure.FailureNodeContainerIndex - texts[i] = fmt.Sprintf("%s [%s]", texts[i], report.Failure.FailureNodeType) - locations[i] = failureLocation - highlightIndex = i - case types.FailureNodeIsLeafNode: - i := len(texts) - 1 - texts[i] = fmt.Sprintf("[%s] %s", report.LeafNodeType, report.LeafNodeText) - locations[i] = failureLocation - highlightIndex = i - default: - //there is no failure, so we highlight the leaf ndoe - highlightIndex = len(texts) - 1 - } - - out := "" - if veryVerbose { - for i := range texts { - if i == highlightIndex { - out += r.fi(uint(i), highlightColor+"{{bold}}%s{{/}}", texts[i]) - } else { - out += r.fi(uint(i), "%s", texts[i]) - } - if len(labels[i]) > 0 { - out += r.f(" {{coral}}[%s]{{/}}", strings.Join(labels[i], ", ")) - } - out += "\n" - out += r.fi(uint(i), "{{gray}}%s{{/}}\n", locations[i]) - } - } else { - for i := range texts { - style := "{{/}}" - if i%2 == 1 { - style = "{{gray}}" - } - if i == highlightIndex { - style = highlightColor + "{{bold}}" - } - out += r.f(style+"%s", texts[i]) - if i < len(texts)-1 { - out += " " - } else { - out += r.f("{{/}}") - } - } - flattenedLabels := report.Labels() - if len(flattenedLabels) > 0 { - out += r.f(" {{coral}}[%s]{{/}}", strings.Join(flattenedLabels, ", ")) - } - out += "\n" - if usePreciseFailureLocation { - out += r.f("{{gray}}%s{{/}}", failureLocation) - } else { - leafLocation := locations[len(locations)-1] - if (report.Failure.FailureNodeLocation != types.CodeLocation{}) && (report.Failure.FailureNodeLocation != leafLocation) { - out += r.fi(1, highlightColor+"[%s]{{/}} {{gray}}%s{{/}}\n", report.Failure.FailureNodeType, report.Failure.FailureNodeLocation) - out += r.fi(1, "{{gray}}[%s] %s{{/}}", report.LeafNodeType, leafLocation) - } else { - out += r.f("{{gray}}%s{{/}}", leafLocation) - } - } - - } - return out -} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go deleted file mode 100644 index 613072ebf1..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go +++ /dev/null @@ -1,149 +0,0 @@ -package reporters - -import ( - "github.com/onsi/ginkgo/v2/config" - "github.com/onsi/ginkgo/v2/types" -) - -// Deprecated: DeprecatedReporter was how Ginkgo V1 provided support for CustomReporters -// this has been removed in V2. -// Please read the documentation at: -// https://onsi.github.io/ginkgo/MIGRATING_TO_V2#removed-custom-reporters -// for Ginkgo's new behavior and for a migration path. -type DeprecatedReporter interface { - SuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) - BeforeSuiteDidRun(setupSummary *types.SetupSummary) - SpecWillRun(specSummary *types.SpecSummary) - SpecDidComplete(specSummary *types.SpecSummary) - AfterSuiteDidRun(setupSummary *types.SetupSummary) - SuiteDidEnd(summary *types.SuiteSummary) -} - -// ReportViaDeprecatedReporter takes a V1 custom reporter and a V2 report and -// calls the custom reporter's methods with appropriately transformed data from the V2 report. -// -// ReportViaDeprecatedReporter should be called in a `ReportAfterSuite()` -// -// Deprecated: ReportViaDeprecatedReporter method exists to help developer bridge between deprecated V1 functionality and the new -// reporting support in V2. It will be removed in a future minor version of Ginkgo. -func ReportViaDeprecatedReporter(reporter DeprecatedReporter, report types.Report) { - conf := config.DeprecatedGinkgoConfigType{ - RandomSeed: report.SuiteConfig.RandomSeed, - RandomizeAllSpecs: report.SuiteConfig.RandomizeAllSpecs, - FocusStrings: report.SuiteConfig.FocusStrings, - SkipStrings: report.SuiteConfig.SkipStrings, - FailOnPending: report.SuiteConfig.FailOnPending, - FailFast: report.SuiteConfig.FailFast, - FlakeAttempts: report.SuiteConfig.FlakeAttempts, - EmitSpecProgress: false, - DryRun: report.SuiteConfig.DryRun, - ParallelNode: report.SuiteConfig.ParallelProcess, - ParallelTotal: report.SuiteConfig.ParallelTotal, - SyncHost: report.SuiteConfig.ParallelHost, - StreamHost: report.SuiteConfig.ParallelHost, - } - - summary := &types.DeprecatedSuiteSummary{ - SuiteDescription: report.SuiteDescription, - SuiteID: report.SuitePath, - - NumberOfSpecsBeforeParallelization: report.PreRunStats.TotalSpecs, - NumberOfTotalSpecs: report.PreRunStats.TotalSpecs, - NumberOfSpecsThatWillBeRun: report.PreRunStats.SpecsThatWillRun, - } - - reporter.SuiteWillBegin(conf, summary) - - for _, spec := range report.SpecReports { - switch spec.LeafNodeType { - case types.NodeTypeBeforeSuite, types.NodeTypeSynchronizedBeforeSuite: - setupSummary := &types.DeprecatedSetupSummary{ - ComponentType: spec.LeafNodeType, - CodeLocation: spec.LeafNodeLocation, - State: spec.State, - RunTime: spec.RunTime, - Failure: failureFor(spec), - CapturedOutput: spec.CombinedOutput(), - SuiteID: report.SuitePath, - } - reporter.BeforeSuiteDidRun(setupSummary) - case types.NodeTypeAfterSuite, types.NodeTypeSynchronizedAfterSuite: - setupSummary := &types.DeprecatedSetupSummary{ - ComponentType: spec.LeafNodeType, - CodeLocation: spec.LeafNodeLocation, - State: spec.State, - RunTime: spec.RunTime, - Failure: failureFor(spec), - CapturedOutput: spec.CombinedOutput(), - SuiteID: report.SuitePath, - } - reporter.AfterSuiteDidRun(setupSummary) - case types.NodeTypeIt: - componentTexts, componentCodeLocations := []string{}, []types.CodeLocation{} - componentTexts = append(componentTexts, spec.ContainerHierarchyTexts...) - componentCodeLocations = append(componentCodeLocations, spec.ContainerHierarchyLocations...) - componentTexts = append(componentTexts, spec.LeafNodeText) - componentCodeLocations = append(componentCodeLocations, spec.LeafNodeLocation) - - specSummary := &types.DeprecatedSpecSummary{ - ComponentTexts: componentTexts, - ComponentCodeLocations: componentCodeLocations, - State: spec.State, - RunTime: spec.RunTime, - Failure: failureFor(spec), - NumberOfSamples: spec.NumAttempts, - CapturedOutput: spec.CombinedOutput(), - SuiteID: report.SuitePath, - } - reporter.SpecWillRun(specSummary) - reporter.SpecDidComplete(specSummary) - - switch spec.State { - case types.SpecStatePending: - summary.NumberOfPendingSpecs += 1 - case types.SpecStateSkipped: - summary.NumberOfSkippedSpecs += 1 - case types.SpecStateFailed, types.SpecStatePanicked, types.SpecStateInterrupted: - summary.NumberOfFailedSpecs += 1 - case types.SpecStatePassed: - summary.NumberOfPassedSpecs += 1 - if spec.NumAttempts > 1 { - summary.NumberOfFlakedSpecs += 1 - } - } - } - } - - summary.SuiteSucceeded = report.SuiteSucceeded - summary.RunTime = report.RunTime - - reporter.SuiteDidEnd(summary) -} - -func failureFor(spec types.SpecReport) types.DeprecatedSpecFailure { - if spec.Failure.IsZero() { - return types.DeprecatedSpecFailure{} - } - - index := 0 - switch spec.Failure.FailureNodeContext { - case types.FailureNodeInContainer: - index = spec.Failure.FailureNodeContainerIndex - case types.FailureNodeAtTopLevel: - index = -1 - case types.FailureNodeIsLeafNode: - index = len(spec.ContainerHierarchyTexts) - 1 - if spec.LeafNodeText != "" { - index += 1 - } - } - - return types.DeprecatedSpecFailure{ - Message: spec.Failure.Message, - Location: spec.Failure.Location, - ForwardedPanic: spec.Failure.ForwardedPanic, - ComponentIndex: index, - ComponentType: spec.Failure.FailureNodeType, - ComponentCodeLocation: spec.Failure.FailureNodeLocation, - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go deleted file mode 100644 index 7f96c450fe..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go +++ /dev/null @@ -1,60 +0,0 @@ -package reporters - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/onsi/ginkgo/v2/types" -) - -//GenerateJSONReport produces a JSON-formatted report at the passed in destination -func GenerateJSONReport(report types.Report, destination string) error { - f, err := os.Create(destination) - if err != nil { - return err - } - enc := json.NewEncoder(f) - enc.SetIndent("", " ") - err = enc.Encode([]types.Report{ - report, - }) - if err != nil { - return err - } - return f.Close() -} - -//MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources -//It skips over reports that fail to decode but reports on them via the returned messages []string -func MergeAndCleanupJSONReports(sources []string, destination string) ([]string, error) { - messages := []string{} - allReports := []types.Report{} - for _, source := range sources { - reports := []types.Report{} - data, err := os.ReadFile(source) - if err != nil { - messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) - continue - } - err = json.Unmarshal(data, &reports) - if err != nil { - messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) - continue - } - os.Remove(source) - allReports = append(allReports, reports...) - } - - f, err := os.Create(destination) - if err != nil { - return messages, err - } - enc := json.NewEncoder(f) - enc.SetIndent("", " ") - err = enc.Encode(allReports) - if err != nil { - return messages, err - } - return messages, f.Close() -} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go deleted file mode 100644 index 592d7f614b..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go +++ /dev/null @@ -1,369 +0,0 @@ -/* - -JUnit XML Reporter for Ginkgo - -For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output - -The schema used for the generated JUnit xml file was adapted from https://llg.cubic.org/docs/junit/ - -*/ - -package reporters - -import ( - "encoding/xml" - "fmt" - "os" - "strings" - - "github.com/onsi/ginkgo/v2/config" - "github.com/onsi/ginkgo/v2/types" -) - -type JunitReportConfig struct { - // Spec States for which no timeline should be emitted for system-err - // set this to types.SpecStatePassed|types.SpecStateSkipped|types.SpecStatePending to only match failing specs - OmitTimelinesForSpecState types.SpecState - - // Enable OmitFailureMessageAttr to prevent failure messages appearing in the "message" attribute of the Failure and Error tags - OmitFailureMessageAttr bool - - //Enable OmitCapturedStdOutErr to prevent captured stdout/stderr appearing in system-out - OmitCapturedStdOutErr bool - - // Enable OmitSpecLabels to prevent labels from appearing in the spec name - OmitSpecLabels bool - - // Enable OmitLeafNodeType to prevent the spec leaf node type from appearing in the spec name - OmitLeafNodeType bool - - // Enable OmitSuiteSetupNodes to prevent the creation of testcase entries for setup nodes - OmitSuiteSetupNodes bool -} - -type JUnitTestSuites struct { - XMLName xml.Name `xml:"testsuites"` - // Tests maps onto the total number of specs in all test suites (this includes any suite nodes such as BeforeSuite) - Tests int `xml:"tests,attr"` - // Disabled maps onto specs that are pending and/or skipped - Disabled int `xml:"disabled,attr"` - // Errors maps onto specs that panicked or were interrupted - Errors int `xml:"errors,attr"` - // Failures maps onto specs that failed - Failures int `xml:"failures,attr"` - // Time is the time in seconds to execute all test suites - Time float64 `xml:"time,attr"` - - //The set of all test suites - TestSuites []JUnitTestSuite `xml:"testsuite"` -} - -type JUnitTestSuite struct { - // Name maps onto the description of the test suite - maps onto Report.SuiteDescription - Name string `xml:"name,attr"` - // Package maps onto the absolute path to the test suite - maps onto Report.SuitePath - Package string `xml:"package,attr"` - // Tests maps onto the total number of specs in the test suite (this includes any suite nodes such as BeforeSuite) - Tests int `xml:"tests,attr"` - // Disabled maps onto specs that are pending - Disabled int `xml:"disabled,attr"` - // Skiped maps onto specs that are skipped - Skipped int `xml:"skipped,attr"` - // Errors maps onto specs that panicked or were interrupted - Errors int `xml:"errors,attr"` - // Failures maps onto specs that failed - Failures int `xml:"failures,attr"` - // Time is the time in seconds to execute all the test suite - maps onto Report.RunTime - Time float64 `xml:"time,attr"` - // Timestamp is the ISO 8601 formatted start-time of the suite - maps onto Report.StartTime - Timestamp string `xml:"timestamp,attr"` - - //Properties captures the information stored in the rest of the Report type (including SuiteConfig) as key-value pairs - Properties JUnitProperties `xml:"properties"` - - //TestCases capture the individual specs - TestCases []JUnitTestCase `xml:"testcase"` -} - -type JUnitProperties struct { - Properties []JUnitProperty `xml:"property"` -} - -func (jup JUnitProperties) WithName(name string) string { - for _, property := range jup.Properties { - if property.Name == name { - return property.Value - } - } - return "" -} - -type JUnitProperty struct { - Name string `xml:"name,attr"` - Value string `xml:"value,attr"` -} - -type JUnitTestCase struct { - // Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()" - Name string `xml:"name,attr"` - // Classname maps onto the name of the test suite - equivalent to Report.SuiteDescription - Classname string `xml:"classname,attr"` - // Status maps onto the string representation of SpecReport.State - Status string `xml:"status,attr"` - // Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime - Time float64 `xml:"time,attr"` - //Skipped is populated with a message if the test was skipped or pending - Skipped *JUnitSkipped `xml:"skipped,omitempty"` - //Error is populated if the test panicked or was interrupted - Error *JUnitError `xml:"error,omitempty"` - //Failure is populated if the test failed - Failure *JUnitFailure `xml:"failure,omitempty"` - //SystemOut maps onto any captured stdout/stderr output - maps onto SpecReport.CapturedStdOutErr - SystemOut string `xml:"system-out,omitempty"` - //SystemOut maps onto any captured GinkgoWriter output - maps onto SpecReport.CapturedGinkgoWriterOutput - SystemErr string `xml:"system-err,omitempty"` -} - -type JUnitSkipped struct { - // Message maps onto "pending" if the test was marked pending, "skipped" if the test was marked skipped, and "skipped - REASON" if the user called Skip(REASON) - Message string `xml:"message,attr"` -} - -type JUnitError struct { - //Message maps onto the panic/exception thrown - equivalent to SpecReport.Failure.ForwardedPanic - or to "interrupted" - Message string `xml:"message,attr"` - //Type is one of "panicked" or "interrupted" - Type string `xml:"type,attr"` - //Description maps onto the captured stack trace for a panic, or the failure message for an interrupt which will include the dump of running goroutines - Description string `xml:",chardata"` -} - -type JUnitFailure struct { - //Message maps onto the failure message - equivalent to SpecReport.Failure.Message - Message string `xml:"message,attr"` - //Type is "failed" - Type string `xml:"type,attr"` - //Description maps onto the location and stack trace of the failure - Description string `xml:",chardata"` -} - -func GenerateJUnitReport(report types.Report, dst string) error { - return GenerateJUnitReportWithConfig(report, dst, JunitReportConfig{}) -} - -func GenerateJUnitReportWithConfig(report types.Report, dst string, config JunitReportConfig) error { - suite := JUnitTestSuite{ - Name: report.SuiteDescription, - Package: report.SuitePath, - Time: report.RunTime.Seconds(), - Timestamp: report.StartTime.Format("2006-01-02T15:04:05"), - Properties: JUnitProperties{ - Properties: []JUnitProperty{ - {"SuiteSucceeded", fmt.Sprintf("%t", report.SuiteSucceeded)}, - {"SuiteHasProgrammaticFocus", fmt.Sprintf("%t", report.SuiteHasProgrammaticFocus)}, - {"SpecialSuiteFailureReason", strings.Join(report.SpecialSuiteFailureReasons, ",")}, - {"SuiteLabels", fmt.Sprintf("[%s]", strings.Join(report.SuiteLabels, ","))}, - {"RandomSeed", fmt.Sprintf("%d", report.SuiteConfig.RandomSeed)}, - {"RandomizeAllSpecs", fmt.Sprintf("%t", report.SuiteConfig.RandomizeAllSpecs)}, - {"LabelFilter", report.SuiteConfig.LabelFilter}, - {"FocusStrings", strings.Join(report.SuiteConfig.FocusStrings, ",")}, - {"SkipStrings", strings.Join(report.SuiteConfig.SkipStrings, ",")}, - {"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")}, - {"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")}, - {"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)}, - {"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)}, - {"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)}, - {"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)}, - {"ParallelTotal", fmt.Sprintf("%d", report.SuiteConfig.ParallelTotal)}, - {"OutputInterceptorMode", report.SuiteConfig.OutputInterceptorMode}, - }, - }, - } - for _, spec := range report.SpecReports { - if config.OmitSuiteSetupNodes && spec.LeafNodeType != types.NodeTypeIt { - continue - } - name := fmt.Sprintf("[%s]", spec.LeafNodeType) - if config.OmitLeafNodeType { - name = "" - } - if spec.FullText() != "" { - name = name + " " + spec.FullText() - } - labels := spec.Labels() - if len(labels) > 0 && !config.OmitSpecLabels { - name = name + " [" + strings.Join(labels, ", ") + "]" - } - name = strings.TrimSpace(name) - - test := JUnitTestCase{ - Name: name, - Classname: report.SuiteDescription, - Status: spec.State.String(), - Time: spec.RunTime.Seconds(), - } - if !spec.State.Is(config.OmitTimelinesForSpecState) { - test.SystemErr = systemErrForUnstructuredReporters(spec) - } - if !config.OmitCapturedStdOutErr { - test.SystemOut = systemOutForUnstructuredReporters(spec) - } - suite.Tests += 1 - - switch spec.State { - case types.SpecStateSkipped: - message := "skipped" - if spec.Failure.Message != "" { - message += " - " + spec.Failure.Message - } - test.Skipped = &JUnitSkipped{Message: message} - suite.Skipped += 1 - case types.SpecStatePending: - test.Skipped = &JUnitSkipped{Message: "pending"} - suite.Disabled += 1 - case types.SpecStateFailed: - test.Failure = &JUnitFailure{ - Message: spec.Failure.Message, - Type: "failed", - Description: failureDescriptionForUnstructuredReporters(spec), - } - if config.OmitFailureMessageAttr { - test.Failure.Message = "" - } - suite.Failures += 1 - case types.SpecStateTimedout: - test.Failure = &JUnitFailure{ - Message: spec.Failure.Message, - Type: "timedout", - Description: failureDescriptionForUnstructuredReporters(spec), - } - if config.OmitFailureMessageAttr { - test.Failure.Message = "" - } - suite.Failures += 1 - case types.SpecStateInterrupted: - test.Error = &JUnitError{ - Message: spec.Failure.Message, - Type: "interrupted", - Description: failureDescriptionForUnstructuredReporters(spec), - } - if config.OmitFailureMessageAttr { - test.Error.Message = "" - } - suite.Errors += 1 - case types.SpecStateAborted: - test.Failure = &JUnitFailure{ - Message: spec.Failure.Message, - Type: "aborted", - Description: failureDescriptionForUnstructuredReporters(spec), - } - if config.OmitFailureMessageAttr { - test.Failure.Message = "" - } - suite.Errors += 1 - case types.SpecStatePanicked: - test.Error = &JUnitError{ - Message: spec.Failure.ForwardedPanic, - Type: "panicked", - Description: failureDescriptionForUnstructuredReporters(spec), - } - if config.OmitFailureMessageAttr { - test.Error.Message = "" - } - suite.Errors += 1 - } - - suite.TestCases = append(suite.TestCases, test) - } - - junitReport := JUnitTestSuites{ - Tests: suite.Tests, - Disabled: suite.Disabled + suite.Skipped, - Errors: suite.Errors, - Failures: suite.Failures, - Time: suite.Time, - TestSuites: []JUnitTestSuite{suite}, - } - - f, err := os.Create(dst) - if err != nil { - return err - } - f.WriteString(xml.Header) - encoder := xml.NewEncoder(f) - encoder.Indent(" ", " ") - encoder.Encode(junitReport) - - return f.Close() -} - -func MergeAndCleanupJUnitReports(sources []string, dst string) ([]string, error) { - messages := []string{} - mergedReport := JUnitTestSuites{} - for _, source := range sources { - report := JUnitTestSuites{} - f, err := os.Open(source) - if err != nil { - messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) - continue - } - err = xml.NewDecoder(f).Decode(&report) - if err != nil { - messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) - continue - } - os.Remove(source) - - mergedReport.Tests += report.Tests - mergedReport.Disabled += report.Disabled - mergedReport.Errors += report.Errors - mergedReport.Failures += report.Failures - mergedReport.Time += report.Time - mergedReport.TestSuites = append(mergedReport.TestSuites, report.TestSuites...) - } - - f, err := os.Create(dst) - if err != nil { - return messages, err - } - f.WriteString(xml.Header) - encoder := xml.NewEncoder(f) - encoder.Indent(" ", " ") - encoder.Encode(mergedReport) - - return messages, f.Close() -} - -func failureDescriptionForUnstructuredReporters(spec types.SpecReport) string { - out := &strings.Builder{} - NewDefaultReporter(types.ReporterConfig{NoColor: true, VeryVerbose: true}, out).emitFailure(0, spec.State, spec.Failure, true) - if len(spec.AdditionalFailures) > 0 { - out.WriteString("\nThere were additional failures detected after the initial failure. These are visible in the timeline\n") - } - return out.String() -} - -func systemErrForUnstructuredReporters(spec types.SpecReport) string { - return RenderTimeline(spec, true) -} - -func RenderTimeline(spec types.SpecReport, noColor bool) string { - out := &strings.Builder{} - NewDefaultReporter(types.ReporterConfig{NoColor: noColor, VeryVerbose: true}, out).emitTimeline(0, spec, spec.Timeline()) - return out.String() -} - -func systemOutForUnstructuredReporters(spec types.SpecReport) string { - return spec.CapturedStdOutErr -} - -// Deprecated JUnitReporter (so folks can still compile their suites) -type JUnitReporter struct{} - -func NewJUnitReporter(_ string) *JUnitReporter { return &JUnitReporter{} } -func (reporter *JUnitReporter) SuiteWillBegin(_ config.GinkgoConfigType, _ *types.SuiteSummary) {} -func (reporter *JUnitReporter) BeforeSuiteDidRun(_ *types.SetupSummary) {} -func (reporter *JUnitReporter) SpecWillRun(_ *types.SpecSummary) {} -func (reporter *JUnitReporter) SpecDidComplete(_ *types.SpecSummary) {} -func (reporter *JUnitReporter) AfterSuiteDidRun(_ *types.SetupSummary) {} -func (reporter *JUnitReporter) SuiteDidEnd(_ *types.SuiteSummary) {} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go deleted file mode 100644 index 5e726c464e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go +++ /dev/null @@ -1,29 +0,0 @@ -package reporters - -import ( - "github.com/onsi/ginkgo/v2/types" -) - -type Reporter interface { - SuiteWillBegin(report types.Report) - WillRun(report types.SpecReport) - DidRun(report types.SpecReport) - SuiteDidEnd(report types.Report) - - //Timeline emission - EmitFailure(state types.SpecState, failure types.Failure) - EmitProgressReport(progressReport types.ProgressReport) - EmitReportEntry(entry types.ReportEntry) - EmitSpecEvent(event types.SpecEvent) -} - -type NoopReporter struct{} - -func (n NoopReporter) SuiteWillBegin(report types.Report) {} -func (n NoopReporter) WillRun(report types.SpecReport) {} -func (n NoopReporter) DidRun(report types.SpecReport) {} -func (n NoopReporter) SuiteDidEnd(report types.Report) {} -func (n NoopReporter) EmitFailure(state types.SpecState, failure types.Failure) {} -func (n NoopReporter) EmitProgressReport(progressReport types.ProgressReport) {} -func (n NoopReporter) EmitReportEntry(entry types.ReportEntry) {} -func (n NoopReporter) EmitSpecEvent(event types.SpecEvent) {} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go deleted file mode 100644 index c1863496dc..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go +++ /dev/null @@ -1,101 +0,0 @@ -/* - -TeamCity Reporter for Ginkgo - -Makes use of TeamCity's support for Service Messages -http://confluence.jetbrains.com/display/TCD7/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ReportingTests -*/ - -package reporters - -import ( - "fmt" - "os" - "strings" - - "github.com/onsi/ginkgo/v2/types" -) - -func tcEscape(s string) string { - s = strings.ReplaceAll(s, "|", "||") - s = strings.ReplaceAll(s, "'", "|'") - s = strings.ReplaceAll(s, "\n", "|n") - s = strings.ReplaceAll(s, "\r", "|r") - s = strings.ReplaceAll(s, "[", "|[") - s = strings.ReplaceAll(s, "]", "|]") - return s -} - -func GenerateTeamcityReport(report types.Report, dst string) error { - f, err := os.Create(dst) - if err != nil { - return err - } - - name := report.SuiteDescription - labels := report.SuiteLabels - if len(labels) > 0 { - name = name + " [" + strings.Join(labels, ", ") + "]" - } - fmt.Fprintf(f, "##teamcity[testSuiteStarted name='%s']\n", tcEscape(name)) - for _, spec := range report.SpecReports { - name := fmt.Sprintf("[%s]", spec.LeafNodeType) - if spec.FullText() != "" { - name = name + " " + spec.FullText() - } - labels := spec.Labels() - if len(labels) > 0 { - name = name + " [" + strings.Join(labels, ", ") + "]" - } - - name = tcEscape(name) - fmt.Fprintf(f, "##teamcity[testStarted name='%s']\n", name) - switch spec.State { - case types.SpecStatePending: - fmt.Fprintf(f, "##teamcity[testIgnored name='%s' message='pending']\n", name) - case types.SpecStateSkipped: - message := "skipped" - if spec.Failure.Message != "" { - message += " - " + spec.Failure.Message - } - fmt.Fprintf(f, "##teamcity[testIgnored name='%s' message='%s']\n", name, tcEscape(message)) - case types.SpecStateFailed: - details := failureDescriptionForUnstructuredReporters(spec) - fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='failed - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) - case types.SpecStatePanicked: - details := failureDescriptionForUnstructuredReporters(spec) - fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='panicked - %s' details='%s']\n", name, tcEscape(spec.Failure.ForwardedPanic), tcEscape(details)) - case types.SpecStateTimedout: - details := failureDescriptionForUnstructuredReporters(spec) - fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='timedout - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) - case types.SpecStateInterrupted: - details := failureDescriptionForUnstructuredReporters(spec) - fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='interrupted - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) - case types.SpecStateAborted: - details := failureDescriptionForUnstructuredReporters(spec) - fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='aborted - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) - } - - fmt.Fprintf(f, "##teamcity[testStdOut name='%s' out='%s']\n", name, tcEscape(systemOutForUnstructuredReporters(spec))) - fmt.Fprintf(f, "##teamcity[testStdErr name='%s' out='%s']\n", name, tcEscape(systemErrForUnstructuredReporters(spec))) - fmt.Fprintf(f, "##teamcity[testFinished name='%s' duration='%d']\n", name, int(spec.RunTime.Seconds()*1000.0)) - } - fmt.Fprintf(f, "##teamcity[testSuiteFinished name='%s']\n", tcEscape(report.SuiteDescription)) - - return f.Close() -} - -func MergeAndCleanupTeamcityReports(sources []string, dst string) ([]string, error) { - messages := []string{} - merged := []byte{} - for _, source := range sources { - data, err := os.ReadFile(source) - if err != nil { - messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) - continue - } - os.Remove(source) - merged = append(merged, data...) - } - return messages, os.WriteFile(dst, merged, 0666) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/code_location.go b/vendor/github.com/onsi/ginkgo/v2/types/code_location.go deleted file mode 100644 index 9cd5768170..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/code_location.go +++ /dev/null @@ -1,159 +0,0 @@ -package types - -import ( - "fmt" - "os" - "regexp" - "runtime" - "runtime/debug" - "strings" - "sync" -) - -type CodeLocation struct { - FileName string `json:",omitempty"` - LineNumber int `json:",omitempty"` - FullStackTrace string `json:",omitempty"` - CustomMessage string `json:",omitempty"` -} - -func (codeLocation CodeLocation) String() string { - if codeLocation.CustomMessage != "" { - return codeLocation.CustomMessage - } - return fmt.Sprintf("%s:%d", codeLocation.FileName, codeLocation.LineNumber) -} - -func (codeLocation CodeLocation) ContentsOfLine() string { - if codeLocation.CustomMessage != "" { - return "" - } - contents, err := os.ReadFile(codeLocation.FileName) - if err != nil { - return "" - } - lines := strings.Split(string(contents), "\n") - if len(lines) < codeLocation.LineNumber { - return "" - } - return lines[codeLocation.LineNumber-1] -} - -type codeLocationLocator struct { - pcs map[uintptr]bool - helpers map[string]bool - lock *sync.Mutex -} - -func (c *codeLocationLocator) addHelper(pc uintptr) { - c.lock.Lock() - defer c.lock.Unlock() - - if c.pcs[pc] { - return - } - c.lock.Unlock() - f := runtime.FuncForPC(pc) - c.lock.Lock() - if f == nil { - return - } - c.helpers[f.Name()] = true - c.pcs[pc] = true -} - -func (c *codeLocationLocator) hasHelper(name string) bool { - c.lock.Lock() - defer c.lock.Unlock() - return c.helpers[name] -} - -func (c *codeLocationLocator) getCodeLocation(skip int) CodeLocation { - pc := make([]uintptr, 40) - n := runtime.Callers(skip+2, pc) - if n == 0 { - return CodeLocation{} - } - pc = pc[:n] - frames := runtime.CallersFrames(pc) - for { - frame, more := frames.Next() - if !c.hasHelper(frame.Function) { - return CodeLocation{FileName: frame.File, LineNumber: frame.Line} - } - if !more { - break - } - } - return CodeLocation{} -} - -var clLocator = &codeLocationLocator{ - pcs: map[uintptr]bool{}, - helpers: map[string]bool{}, - lock: &sync.Mutex{}, -} - -// MarkAsHelper is used by GinkgoHelper to mark the caller (appropriately offset by skip)as a helper. You can use this directly if you need to provide an optional `skip` to mark functions further up the call stack as helpers. -func MarkAsHelper(optionalSkip ...int) { - skip := 1 - if len(optionalSkip) > 0 { - skip += optionalSkip[0] - } - pc, _, _, ok := runtime.Caller(skip) - if ok { - clLocator.addHelper(pc) - } -} - -func NewCustomCodeLocation(message string) CodeLocation { - return CodeLocation{ - CustomMessage: message, - } -} - -func NewCodeLocation(skip int) CodeLocation { - return clLocator.getCodeLocation(skip + 1) -} - -func NewCodeLocationWithStackTrace(skip int) CodeLocation { - cl := clLocator.getCodeLocation(skip + 1) - cl.FullStackTrace = PruneStack(string(debug.Stack()), skip+1) - return cl -} - -// PruneStack removes references to functions that are internal to Ginkgo -// and the Go runtime from a stack string and a certain number of stack entries -// at the beginning of the stack. The stack string has the format -// as returned by runtime/debug.Stack. The leading goroutine information is -// optional and always removed if present. Beware that runtime/debug.Stack -// adds itself as first entry, so typically skip must be >= 1 to remove that -// entry. -func PruneStack(fullStackTrace string, skip int) string { - stack := strings.Split(fullStackTrace, "\n") - // Ensure that the even entries are the method names and the - // odd entries the source code information. - if len(stack) > 0 && strings.HasPrefix(stack[0], "goroutine ") { - // Ignore "goroutine 29 [running]:" line. - stack = stack[1:] - } - // The "+1" is for skipping over the initial entry, which is - // runtime/debug.Stack() itself. - if len(stack) > 2*(skip+1) { - stack = stack[2*(skip+1):] - } - prunedStack := []string{} - if os.Getenv("GINKGO_PRUNE_STACK") == "FALSE" { - prunedStack = stack - } else { - re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) - for i := 0; i < len(stack)/2; i++ { - // We filter out based on the source code file name. - if !re.Match([]byte(stack[i*2+1])) { - prunedStack = append(prunedStack, stack[i*2]) - prunedStack = append(prunedStack, stack[i*2+1]) - } - } - } - return strings.Join(prunedStack, "\n") -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go deleted file mode 100644 index 1014c7b49f..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/config.go +++ /dev/null @@ -1,757 +0,0 @@ -/* -Ginkgo accepts a number of configuration options. -These are documented [here](http://onsi.github.io/ginkgo/#the-ginkgo-cli) -*/ - -package types - -import ( - "flag" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "time" -) - -// Configuration controlling how an individual test suite is run -type SuiteConfig struct { - RandomSeed int64 - RandomizeAllSpecs bool - FocusStrings []string - SkipStrings []string - FocusFiles []string - SkipFiles []string - LabelFilter string - FailOnPending bool - FailFast bool - FlakeAttempts int - DryRun bool - PollProgressAfter time.Duration - PollProgressInterval time.Duration - Timeout time.Duration - EmitSpecProgress bool // this is deprecated but its removal is causing compile issue for some users that were setting it manually - OutputInterceptorMode string - SourceRoots []string - GracePeriod time.Duration - - ParallelProcess int - ParallelTotal int - ParallelHost string -} - -func NewDefaultSuiteConfig() SuiteConfig { - return SuiteConfig{ - RandomSeed: time.Now().Unix(), - Timeout: time.Hour, - ParallelProcess: 1, - ParallelTotal: 1, - GracePeriod: 30 * time.Second, - } -} - -type VerbosityLevel uint - -const ( - VerbosityLevelSuccinct VerbosityLevel = iota - VerbosityLevelNormal - VerbosityLevelVerbose - VerbosityLevelVeryVerbose -) - -func (vl VerbosityLevel) GT(comp VerbosityLevel) bool { - return vl > comp -} - -func (vl VerbosityLevel) GTE(comp VerbosityLevel) bool { - return vl >= comp -} - -func (vl VerbosityLevel) Is(comp VerbosityLevel) bool { - return vl == comp -} - -func (vl VerbosityLevel) LTE(comp VerbosityLevel) bool { - return vl <= comp -} - -func (vl VerbosityLevel) LT(comp VerbosityLevel) bool { - return vl < comp -} - -// Configuration for Ginkgo's reporter -type ReporterConfig struct { - NoColor bool - Succinct bool - Verbose bool - VeryVerbose bool - FullTrace bool - ShowNodeEvents bool - - JSONReport string - JUnitReport string - TeamcityReport string -} - -func (rc ReporterConfig) Verbosity() VerbosityLevel { - if rc.Succinct { - return VerbosityLevelSuccinct - } else if rc.Verbose { - return VerbosityLevelVerbose - } else if rc.VeryVerbose { - return VerbosityLevelVeryVerbose - } - return VerbosityLevelNormal -} - -func (rc ReporterConfig) WillGenerateReport() bool { - return rc.JSONReport != "" || rc.JUnitReport != "" || rc.TeamcityReport != "" -} - -func NewDefaultReporterConfig() ReporterConfig { - return ReporterConfig{} -} - -// Configuration for the Ginkgo CLI -type CLIConfig struct { - //for build, run, and watch - Recurse bool - SkipPackage string - RequireSuite bool - NumCompilers int - - //for run and watch only - Procs int - Parallel bool - AfterRunHook string - OutputDir string - KeepSeparateCoverprofiles bool - KeepSeparateReports bool - - //for run only - KeepGoing bool - UntilItFails bool - Repeat int - RandomizeSuites bool - - //for watch only - Depth int - WatchRegExp string -} - -func NewDefaultCLIConfig() CLIConfig { - return CLIConfig{ - Depth: 1, - WatchRegExp: `\.go$`, - } -} - -func (g CLIConfig) ComputedProcs() int { - if g.Procs > 0 { - return g.Procs - } - - n := 1 - if g.Parallel { - n = runtime.NumCPU() - if n > 4 { - n = n - 1 - } - } - return n -} - -func (g CLIConfig) ComputedNumCompilers() int { - if g.NumCompilers > 0 { - return g.NumCompilers - } - - return runtime.NumCPU() -} - -// Configuration for the Ginkgo CLI capturing available go flags -// A subset of Go flags are exposed by Ginkgo. Some are available at compile time (e.g. ginkgo build) and others only at run time (e.g. ginkgo run - which has both build and run time flags). -// More details can be found at: -// https://docs.google.com/spreadsheets/d/1zkp-DS4hU4sAJl5eHh1UmgwxCPQhf3s5a8fbiOI8tJU/ -type GoFlagsConfig struct { - //build-time flags for code-and-performance analysis - Race bool - Cover bool - CoverMode string - CoverPkg string - Vet string - - //run-time flags for code-and-performance analysis - BlockProfile string - BlockProfileRate int - CoverProfile string - CPUProfile string - MemProfile string - MemProfileRate int - MutexProfile string - MutexProfileFraction int - Trace string - - //build-time flags for building - A bool - ASMFlags string - BuildMode string - Compiler string - GCCGoFlags string - GCFlags string - InstallSuffix string - LDFlags string - LinkShared bool - Mod string - N bool - ModFile string - ModCacheRW bool - MSan bool - PkgDir string - Tags string - TrimPath bool - ToolExec string - Work bool - X bool -} - -func NewDefaultGoFlagsConfig() GoFlagsConfig { - return GoFlagsConfig{} -} - -func (g GoFlagsConfig) BinaryMustBePreserved() bool { - return g.BlockProfile != "" || g.CPUProfile != "" || g.MemProfile != "" || g.MutexProfile != "" -} - -// Configuration that were deprecated in 2.0 -type deprecatedConfig struct { - DebugParallel bool - NoisySkippings bool - NoisyPendings bool - RegexScansFilePath bool - SlowSpecThresholdWithFLoatUnits float64 - Stream bool - Notify bool - EmitSpecProgress bool - SlowSpecThreshold time.Duration - AlwaysEmitGinkgoWriter bool -} - -// Flags - -// Flags sections used by both the CLI and the Ginkgo test process -var FlagSections = GinkgoFlagSections{ - {Key: "multiple-suites", Style: "{{dark-green}}", Heading: "Running Multiple Test Suites"}, - {Key: "order", Style: "{{green}}", Heading: "Controlling Test Order"}, - {Key: "parallel", Style: "{{yellow}}", Heading: "Controlling Test Parallelism"}, - {Key: "low-level-parallel", Style: "{{yellow}}", Heading: "Controlling Test Parallelism", - Description: "These are set by the Ginkgo CLI, {{red}}{{bold}}do not set them manually{{/}} via go test.\nUse ginkgo -p or ginkgo -procs=N instead."}, - {Key: "filter", Style: "{{cyan}}", Heading: "Filtering Tests"}, - {Key: "failure", Style: "{{red}}", Heading: "Failure Handling"}, - {Key: "output", Style: "{{magenta}}", Heading: "Controlling Output Formatting"}, - {Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis"}, - {Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis"}, - {Key: "debug", Style: "{{blue}}", Heading: "Debugging Tests", - Description: "In addition to these flags, Ginkgo supports a few debugging environment variables. To change the parallel server protocol set {{blue}}GINKGO_PARALLEL_PROTOCOL{{/}} to {{bold}}HTTP{{/}}. To avoid pruning callstacks set {{blue}}GINKGO_PRUNE_STACK{{/}} to {{bold}}FALSE{{/}}."}, - {Key: "watch", Style: "{{light-yellow}}", Heading: "Controlling Ginkgo Watch"}, - {Key: "misc", Style: "{{light-gray}}", Heading: "Miscellaneous"}, - {Key: "go-build", Style: "{{light-gray}}", Heading: "Go Build Flags", Succinct: true, - Description: "These flags are inherited from go build. Run {{bold}}ginkgo help build{{/}} for more detailed flag documentation."}, -} - -// SuiteConfigFlags provides flags for the Ginkgo test process, and CLI -var SuiteConfigFlags = GinkgoFlags{ - {KeyPath: "S.RandomSeed", Name: "seed", SectionKey: "order", UsageDefaultValue: "randomly generated by Ginkgo", - Usage: "The seed used to randomize the spec suite."}, - {KeyPath: "S.RandomizeAllSpecs", Name: "randomize-all", SectionKey: "order", DeprecatedName: "randomizeAllSpecs", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When containers."}, - - {KeyPath: "S.FailOnPending", Name: "fail-on-pending", SectionKey: "failure", DeprecatedName: "failOnPending", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will mark the test suite as failed if any specs are pending."}, - {KeyPath: "S.FailFast", Name: "fail-fast", SectionKey: "failure", DeprecatedName: "failFast", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will stop running a test suite after a failure occurs."}, - {KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags", - Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."}, - - {KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."}, - {KeyPath: "S.PollProgressAfter", Name: "poll-progress-after", SectionKey: "debug", UsageDefaultValue: "0", - Usage: "Emit node progress reports periodically if node hasn't completed after this duration."}, - {KeyPath: "S.PollProgressInterval", Name: "poll-progress-interval", SectionKey: "debug", UsageDefaultValue: "10s", - Usage: "The rate at which to emit node progress reports after poll-progress-after has elapsed."}, - {KeyPath: "S.SourceRoots", Name: "source-root", SectionKey: "debug", - Usage: "The location to look for source code when generating progress reports. You can pass multiple --source-root flags."}, - {KeyPath: "S.Timeout", Name: "timeout", SectionKey: "debug", UsageDefaultValue: "1h", - Usage: "Test suite fails if it does not complete within the specified timeout."}, - {KeyPath: "S.GracePeriod", Name: "grace-period", SectionKey: "debug", UsageDefaultValue: "30s", - Usage: "When interrupted, Ginkgo will wait for GracePeriod for the current running node to exit before moving on to the next one."}, - {KeyPath: "S.OutputInterceptorMode", Name: "output-interceptor-mode", SectionKey: "debug", UsageArgument: "dup, swap, or none", - Usage: "If set, ginkgo will use the specified output interception strategy when running in parallel. Defaults to dup on unix and swap on windows."}, - - {KeyPath: "S.LabelFilter", Name: "label-filter", SectionKey: "filter", UsageArgument: "expression", - Usage: "If set, ginkgo will only run specs with labels that match the label-filter. The passed-in expression can include boolean operations (!, &&, ||, ','), groupings via '()', and regular expressions '/regexp/'. e.g. '(cat || dog) && !fruit'"}, - {KeyPath: "S.FocusStrings", Name: "focus", SectionKey: "filter", - Usage: "If set, ginkgo will only run specs that match this regular expression. Can be specified multiple times, values are ORed."}, - {KeyPath: "S.SkipStrings", Name: "skip", SectionKey: "filter", - Usage: "If set, ginkgo will only run specs that do not match this regular expression. Can be specified multiple times, values are ORed."}, - {KeyPath: "S.FocusFiles", Name: "focus-file", SectionKey: "filter", UsageArgument: "file (regexp) | file:line | file:lineA-lineB | file:line,line,line", - Usage: "If set, ginkgo will only run specs in matching files. Can be specified multiple times, values are ORed."}, - {KeyPath: "S.SkipFiles", Name: "skip-file", SectionKey: "filter", UsageArgument: "file (regexp) | file:line | file:lineA-lineB | file:line,line,line", - Usage: "If set, ginkgo will skip specs in matching files. Can be specified multiple times, values are ORed."}, - - {KeyPath: "D.RegexScansFilePath", DeprecatedName: "regexScansFilePath", DeprecatedDocLink: "removed--regexscansfilepath", DeprecatedVersion: "2.0.0"}, - {KeyPath: "D.DebugParallel", DeprecatedName: "debug", DeprecatedDocLink: "removed--debug", DeprecatedVersion: "2.0.0"}, - {KeyPath: "D.EmitSpecProgress", DeprecatedName: "progress", SectionKey: "debug", - DeprecatedVersion: "2.5.0", Usage: ". The functionality provided by --progress was confusing and is no longer needed. Use --show-node-events instead to see node entry and exit events included in the timeline of failed and verbose specs. Or you can run with -vv to always see all node events. Lastly, --poll-progress-after and the PollProgressAfter decorator now provide a better mechanism for debugging specs that tend to get stuck."}, -} - -// ParallelConfigFlags provides flags for the Ginkgo test process (not the CLI) -var ParallelConfigFlags = GinkgoFlags{ - {KeyPath: "S.ParallelProcess", Name: "parallel.process", SectionKey: "low-level-parallel", UsageDefaultValue: "1", - Usage: "This worker process's (one-indexed) process number. For running specs in parallel."}, - {KeyPath: "S.ParallelTotal", Name: "parallel.total", SectionKey: "low-level-parallel", UsageDefaultValue: "1", - Usage: "The total number of worker processes. For running specs in parallel."}, - {KeyPath: "S.ParallelHost", Name: "parallel.host", SectionKey: "low-level-parallel", UsageDefaultValue: "set by Ginkgo CLI", - Usage: "The address for the server that will synchronize the processes."}, -} - -// ReporterConfigFlags provides flags for the Ginkgo test process, and CLI -var ReporterConfigFlags = GinkgoFlags{ - {KeyPath: "R.NoColor", Name: "no-color", SectionKey: "output", DeprecatedName: "noColor", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, suppress color output in default reporter."}, - {KeyPath: "R.Verbose", Name: "v", SectionKey: "output", - Usage: "If set, emits more output including GinkgoWriter contents."}, - {KeyPath: "R.VeryVerbose", Name: "vv", SectionKey: "output", - Usage: "If set, emits with maximal verbosity - includes skipped and pending tests."}, - {KeyPath: "R.Succinct", Name: "succinct", SectionKey: "output", - Usage: "If set, default reporter prints out a very succinct report"}, - {KeyPath: "R.FullTrace", Name: "trace", SectionKey: "output", - Usage: "If set, default reporter prints out the full stack trace when a failure occurs"}, - {KeyPath: "R.ShowNodeEvents", Name: "show-node-events", SectionKey: "output", - Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"}, - - {KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output", - Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."}, - {KeyPath: "R.JUnitReport", Name: "junit-report", UsageArgument: "filename.xml", SectionKey: "output", DeprecatedName: "reportFile", DeprecatedDocLink: "improved-reporting-infrastructure", - Usage: "If set, Ginkgo will generate a conformant junit test report in the specified file."}, - {KeyPath: "R.TeamcityReport", Name: "teamcity-report", UsageArgument: "filename", SectionKey: "output", - Usage: "If set, Ginkgo will generate a Teamcity-formatted test report at the specified location."}, - - {KeyPath: "D.SlowSpecThresholdWithFLoatUnits", DeprecatedName: "slowSpecThreshold", DeprecatedDocLink: "changed--slowspecthreshold", - Usage: "use --slow-spec-threshold instead and pass in a duration string (e.g. '5s', not '5.0')"}, - {KeyPath: "D.NoisyPendings", DeprecatedName: "noisyPendings", DeprecatedDocLink: "removed--noisypendings-and--noisyskippings", DeprecatedVersion: "2.0.0"}, - {KeyPath: "D.NoisySkippings", DeprecatedName: "noisySkippings", DeprecatedDocLink: "removed--noisypendings-and--noisyskippings", DeprecatedVersion: "2.0.0"}, - {KeyPath: "D.SlowSpecThreshold", DeprecatedName: "slow-spec-threshold", SectionKey: "output", Usage: "--slow-spec-threshold has been deprecated and will be removed in a future version of Ginkgo. This feature has proved to be more noisy than useful. You can use --poll-progress-after, instead, to get more actionable feedback about potentially slow specs and understand where they might be getting stuck.", DeprecatedVersion: "2.5.0"}, - {KeyPath: "D.AlwaysEmitGinkgoWriter", DeprecatedName: "always-emit-ginkgo-writer", SectionKey: "output", Usage: " - use -v instead, or one of Ginkgo's machine-readable report formats to get GinkgoWriter output for passing specs."}, -} - -// BuildTestSuiteFlagSet attaches to the CommandLine flagset and provides flags for the Ginkgo test process -func BuildTestSuiteFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig) (GinkgoFlagSet, error) { - flags := SuiteConfigFlags.CopyAppend(ParallelConfigFlags...).CopyAppend(ReporterConfigFlags...) - flags = flags.WithPrefix("ginkgo") - bindings := map[string]interface{}{ - "S": suiteConfig, - "R": reporterConfig, - "D": &deprecatedConfig{}, - } - extraGoFlagsSection := GinkgoFlagSection{Style: "{{gray}}", Heading: "Go test flags"} - - return NewAttachedGinkgoFlagSet(flag.CommandLine, flags, bindings, FlagSections, extraGoFlagsSection) -} - -// VetConfig validates that the Ginkgo test process' configuration is sound -func VetConfig(flagSet GinkgoFlagSet, suiteConfig SuiteConfig, reporterConfig ReporterConfig) []error { - errors := []error{} - - if flagSet.WasSet("count") || flagSet.WasSet("test.count") { - flag := flagSet.Lookup("count") - if flag == nil { - flag = flagSet.Lookup("test.count") - } - count, err := strconv.Atoi(flag.Value.String()) - if err != nil || count != 1 { - errors = append(errors, GinkgoErrors.InvalidGoFlagCount()) - } - } - - if flagSet.WasSet("parallel") || flagSet.WasSet("test.parallel") { - errors = append(errors, GinkgoErrors.InvalidGoFlagParallel()) - } - - if suiteConfig.ParallelTotal < 1 { - errors = append(errors, GinkgoErrors.InvalidParallelTotalConfiguration()) - } - - if suiteConfig.ParallelProcess > suiteConfig.ParallelTotal || suiteConfig.ParallelProcess < 1 { - errors = append(errors, GinkgoErrors.InvalidParallelProcessConfiguration()) - } - - if suiteConfig.ParallelTotal > 1 && suiteConfig.ParallelHost == "" { - errors = append(errors, GinkgoErrors.MissingParallelHostConfiguration()) - } - - if suiteConfig.DryRun && suiteConfig.ParallelTotal > 1 { - errors = append(errors, GinkgoErrors.DryRunInParallelConfiguration()) - } - - if suiteConfig.GracePeriod <= 0 { - errors = append(errors, GinkgoErrors.GracePeriodCannotBeZero()) - } - - if len(suiteConfig.FocusFiles) > 0 { - _, err := ParseFileFilters(suiteConfig.FocusFiles) - if err != nil { - errors = append(errors, err) - } - } - - if len(suiteConfig.SkipFiles) > 0 { - _, err := ParseFileFilters(suiteConfig.SkipFiles) - if err != nil { - errors = append(errors, err) - } - } - - if suiteConfig.LabelFilter != "" { - _, err := ParseLabelFilter(suiteConfig.LabelFilter) - if err != nil { - errors = append(errors, err) - } - } - - switch strings.ToLower(suiteConfig.OutputInterceptorMode) { - case "", "dup", "swap", "none": - default: - errors = append(errors, GinkgoErrors.InvalidOutputInterceptorModeConfiguration(suiteConfig.OutputInterceptorMode)) - } - - numVerbosity := 0 - for _, v := range []bool{reporterConfig.Succinct, reporterConfig.Verbose, reporterConfig.VeryVerbose} { - if v { - numVerbosity++ - } - } - if numVerbosity > 1 { - errors = append(errors, GinkgoErrors.ConflictingVerbosityConfiguration()) - } - - return errors -} - -// GinkgoCLISharedFlags provides flags shared by the Ginkgo CLI's build, watch, and run commands -var GinkgoCLISharedFlags = GinkgoFlags{ - {KeyPath: "C.Recurse", Name: "r", SectionKey: "multiple-suites", - Usage: "If set, ginkgo finds and runs test suites under the current directory recursively."}, - {KeyPath: "C.SkipPackage", Name: "skip-package", SectionKey: "multiple-suites", DeprecatedName: "skipPackage", DeprecatedDocLink: "changed-command-line-flags", - UsageArgument: "comma-separated list of packages", - Usage: "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored."}, - {KeyPath: "C.RequireSuite", Name: "require-suite", SectionKey: "failure", DeprecatedName: "requireSuite", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, Ginkgo fails if there are ginkgo tests in a directory but no invocation of RunSpecs."}, - {KeyPath: "C.NumCompilers", Name: "compilers", SectionKey: "multiple-suites", UsageDefaultValue: "0 (will autodetect)", - Usage: "When running multiple packages, the number of concurrent compilations to perform."}, -} - -// GinkgoCLIRunAndWatchFlags provides flags shared by the Ginkgo CLI's build and watch commands (but not run) -var GinkgoCLIRunAndWatchFlags = GinkgoFlags{ - {KeyPath: "C.Procs", Name: "procs", SectionKey: "parallel", UsageDefaultValue: "1 (run in series)", - Usage: "The number of parallel test nodes to run."}, - {KeyPath: "C.Procs", Name: "nodes", SectionKey: "parallel", UsageDefaultValue: "1 (run in series)", - Usage: "--nodes is an alias for --procs"}, - {KeyPath: "C.Parallel", Name: "p", SectionKey: "parallel", - Usage: "If set, ginkgo will run in parallel with an auto-detected number of nodes."}, - {KeyPath: "C.AfterRunHook", Name: "after-run-hook", SectionKey: "misc", DeprecatedName: "afterSuiteHook", DeprecatedDocLink: "changed-command-line-flags", - Usage: "Command to run when a test suite completes."}, - {KeyPath: "C.OutputDir", Name: "output-dir", SectionKey: "output", UsageArgument: "directory", DeprecatedName: "outputdir", DeprecatedDocLink: "improved-profiling-support", - Usage: "A location to place all generated profiles and reports."}, - {KeyPath: "C.KeepSeparateCoverprofiles", Name: "keep-separate-coverprofiles", SectionKey: "code-and-coverage-analysis", - Usage: "If set, Ginkgo does not merge coverprofiles into one monolithic coverprofile. The coverprofiles will remain in their respective package directories or in -output-dir if set."}, - {KeyPath: "C.KeepSeparateReports", Name: "keep-separate-reports", SectionKey: "output", - Usage: "If set, Ginkgo does not merge per-suite reports (e.g. -json-report) into one monolithic report for the entire testrun. The reports will remain in their respective package directories or in -output-dir if set."}, - - {KeyPath: "D.Stream", DeprecatedName: "stream", DeprecatedDocLink: "removed--stream", DeprecatedVersion: "2.0.0"}, - {KeyPath: "D.Notify", DeprecatedName: "notify", DeprecatedDocLink: "removed--notify", DeprecatedVersion: "2.0.0"}, -} - -// GinkgoCLIRunFlags provides flags for Ginkgo CLI's run command that aren't shared by any other commands -var GinkgoCLIRunFlags = GinkgoFlags{ - {KeyPath: "C.KeepGoing", Name: "keep-going", SectionKey: "multiple-suites", DeprecatedName: "keepGoing", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, failures from earlier test suites do not prevent later test suites from running."}, - {KeyPath: "C.UntilItFails", Name: "until-it-fails", SectionKey: "debug", DeprecatedName: "untilItFails", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will keep rerunning test suites until a failure occurs."}, - {KeyPath: "C.Repeat", Name: "repeat", SectionKey: "debug", UsageArgument: "n", UsageDefaultValue: "0 - i.e. no repetition, run only once", - Usage: "The number of times to re-run a test-suite. Useful for debugging flaky tests. If set to N the suite will be run N+1 times and will be required to pass each time."}, - {KeyPath: "C.RandomizeSuites", Name: "randomize-suites", SectionKey: "order", DeprecatedName: "randomizeSuites", DeprecatedDocLink: "changed-command-line-flags", - Usage: "If set, ginkgo will randomize the order in which test suites run."}, -} - -// GinkgoCLIRunFlags provides flags for Ginkgo CLI's watch command that aren't shared by any other commands -var GinkgoCLIWatchFlags = GinkgoFlags{ - {KeyPath: "C.Depth", Name: "depth", SectionKey: "watch", - Usage: "Ginkgo will watch dependencies down to this depth in the dependency tree."}, - {KeyPath: "C.WatchRegExp", Name: "watch-regexp", SectionKey: "watch", DeprecatedName: "watchRegExp", DeprecatedDocLink: "changed-command-line-flags", - UsageArgument: "Regular Expression", - UsageDefaultValue: `\.go$`, - Usage: "Only files matching this regular expression will be watched for changes."}, -} - -// GoBuildFlags provides flags for the Ginkgo CLI build, run, and watch commands that capture go's build-time flags. These are passed to go test -c by the ginkgo CLI -var GoBuildFlags = GinkgoFlags{ - {KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis", - Usage: "enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, linux/ppc64le and linux/arm64 (only for 48-bit VMA)."}, - {KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis", - Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks. If list is empty, "go test" runs "go vet" with a curated list of checks believed to be always worth addressing. If list is "off", "go test" does not run "go vet" at all. Available checks can be found by running 'go doc cmd/vet'`}, - {KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis", - Usage: "Enable coverage analysis. Note that because coverage works by annotating the source code before compilation, compilation and test failures with coverage enabled may report line numbers that don't correspond to the original sources."}, - {KeyPath: "Go.CoverMode", Name: "covermode", UsageArgument: "set,count,atomic", SectionKey: "code-and-coverage-analysis", - Usage: `Set the mode for coverage analysis for the package[s] being tested. 'set': does this statement run? 'count': how many times does this statement run? 'atomic': like count, but correct in multithreaded tests and more expensive (must use atomic with -race). Sets -cover`}, - {KeyPath: "Go.CoverPkg", Name: "coverpkg", UsageArgument: "pattern1,pattern2,pattern3", SectionKey: "code-and-coverage-analysis", - Usage: "Apply coverage analysis in each test to packages matching the patterns. The default is for each test to analyze only the package being tested. See 'go help packages' for a description of package patterns. Sets -cover."}, - - {KeyPath: "Go.A", Name: "a", SectionKey: "go-build", - Usage: "force rebuilding of packages that are already up-to-date."}, - {KeyPath: "Go.ASMFlags", Name: "asmflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", - Usage: "arguments to pass on each go tool asm invocation."}, - {KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build", - Usage: "build mode to use. See 'go help buildmode' for more."}, - {KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build", - Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."}, - {KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", - Usage: "arguments to pass on each gccgo compiler/linker invocation."}, - {KeyPath: "Go.GCFlags", Name: "gcflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", - Usage: "arguments to pass on each go tool compile invocation."}, - {KeyPath: "Go.InstallSuffix", Name: "installsuffix", SectionKey: "go-build", - Usage: "a suffix to use in the name of the package installation directory, in order to keep output separate from default builds. If using the -race flag, the install suffix is automatically set to raceor, if set explicitly, has _race appended to it. Likewise for the -msan flag. Using a -buildmode option that requires non-default compile flags has a similar effect."}, - {KeyPath: "Go.LDFlags", Name: "ldflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", - Usage: "arguments to pass on each go tool link invocation."}, - {KeyPath: "Go.LinkShared", Name: "linkshared", SectionKey: "go-build", - Usage: "build code that will be linked against shared libraries previously created with -buildmode=shared."}, - {KeyPath: "Go.Mod", Name: "mod", UsageArgument: "mode (readonly, vendor, or mod)", SectionKey: "go-build", - Usage: "module download mode to use: readonly, vendor, or mod. See 'go help modules' for more."}, - {KeyPath: "Go.ModCacheRW", Name: "modcacherw", SectionKey: "go-build", - Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."}, - {KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build", - Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`}, - {KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build", - Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."}, - {KeyPath: "Go.N", Name: "n", SectionKey: "go-build", - Usage: "print the commands but do not run them."}, - {KeyPath: "Go.PkgDir", Name: "pkgdir", UsageArgument: "dir", SectionKey: "go-build", - Usage: "install and load all packages from dir instead of the usual locations. For example, when building with a non-standard configuration, use -pkgdir to keep generated packages in a separate location."}, - {KeyPath: "Go.Tags", Name: "tags", UsageArgument: "tag,list", SectionKey: "go-build", - Usage: "a comma-separated list of build tags to consider satisfied during the build. For more information about build tags, see the description of build constraints in the documentation for the go/build package. (Earlier versions of Go used a space-separated list, and that form is deprecated but still recognized.)"}, - {KeyPath: "Go.TrimPath", Name: "trimpath", SectionKey: "go-build", - Usage: `remove all file system paths from the resulting executable. Instead of absolute file system paths, the recorded file names will begin with either "go" (for the standard library), or a module path@version (when using modules), or a plain import path (when using GOPATH).`}, - {KeyPath: "Go.ToolExec", Name: "toolexec", UsageArgument: "'cmd args'", SectionKey: "go-build", - Usage: "a program to use to invoke toolchain programs like vet and asm. For example, instead of running asm, the go command will run cmd args /path/to/asm '."}, - {KeyPath: "Go.Work", Name: "work", SectionKey: "go-build", - Usage: "print the name of the temporary work directory and do not delete it when exiting."}, - {KeyPath: "Go.X", Name: "x", SectionKey: "go-build", - Usage: "print the commands."}, -} - -// GoRunFlags provides flags for the Ginkgo CLI run, and watch commands that capture go's run-time flags. These are passed to the compiled test binary by the ginkgo CLI -var GoRunFlags = GinkgoFlags{ - {KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis", - Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover.`}, - {KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "file", SectionKey: "performance-analysis", - Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`}, - {KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis", - Usage: `Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with rate. See 'go doc runtime.SetBlockProfileRate'. The profiler aims to sample, on average, one blocking event every n nanoseconds the program spends blocked. By default, if -test.blockprofile is set without this flag, all blocking events are recorded, equivalent to -test.blockprofilerate=1.`}, - {KeyPath: "Go.CPUProfile", Name: "cpuprofile", UsageArgument: "file", SectionKey: "performance-analysis", - Usage: `Write a CPU profile to the specified file before exiting. Preserves test binary.`}, - {KeyPath: "Go.MemProfile", Name: "memprofile", UsageArgument: "file", SectionKey: "performance-analysis", - Usage: `Write an allocation profile to the file after all tests have passed. Preserves test binary.`}, - {KeyPath: "Go.MemProfileRate", Name: "memprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis", - Usage: `Enable more precise (and expensive) memory allocation profiles by setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1.`}, - {KeyPath: "Go.MutexProfile", Name: "mutexprofile", UsageArgument: "file", SectionKey: "performance-analysis", - Usage: `Write a mutex contention profile to the specified file when all tests are complete. Preserves test binary.`}, - {KeyPath: "Go.MutexProfileFraction", Name: "mutexprofilefraction", UsageArgument: "n", SectionKey: "performance-analysis", - Usage: `if >= 0, calls runtime.SetMutexProfileFraction() Sample 1 in n stack traces of goroutines holding a contended mutex.`}, - {KeyPath: "Go.Trace", Name: "execution-trace", UsageArgument: "file", ExportAs: "trace", SectionKey: "performance-analysis", - Usage: `Write an execution trace to the specified file before exiting.`}, -} - -// VetAndInitializeCLIAndGoConfig validates that the Ginkgo CLI's configuration is sound -// It returns a potentially mutated copy of the config that rationalizes the configuration to ensure consistency for downstream consumers -func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsConfig) (CLIConfig, GoFlagsConfig, []error) { - errors := []error{} - - if cliConfig.Repeat > 0 && cliConfig.UntilItFails { - errors = append(errors, GinkgoErrors.BothRepeatAndUntilItFails()) - } - - //initialize the output directory - if cliConfig.OutputDir != "" { - err := os.MkdirAll(cliConfig.OutputDir, 0777) - if err != nil { - errors = append(errors, err) - } - } - - //ensure cover mode is configured appropriately - if goFlagsConfig.CoverMode != "" || goFlagsConfig.CoverPkg != "" || goFlagsConfig.CoverProfile != "" { - goFlagsConfig.Cover = true - } - if goFlagsConfig.Cover && goFlagsConfig.CoverProfile == "" { - goFlagsConfig.CoverProfile = "coverprofile.out" - } - - return cliConfig, goFlagsConfig, errors -} - -// GenerateGoTestCompileArgs is used by the Ginkgo CLI to generate command line arguments to pass to the go test -c command when compiling the test -func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string, packageToBuild string, pathToInvocationPath string) ([]string, error) { - // if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure - // the built test binary can generate a coverprofile - if goFlagsConfig.CoverProfile != "" { - goFlagsConfig.Cover = true - } - - if goFlagsConfig.CoverPkg != "" { - coverPkgs := strings.Split(goFlagsConfig.CoverPkg, ",") - adjustedCoverPkgs := make([]string, len(coverPkgs)) - for i, coverPkg := range coverPkgs { - coverPkg = strings.Trim(coverPkg, " ") - if strings.HasPrefix(coverPkg, "./") { - // this is a relative coverPkg - we need to reroot it - adjustedCoverPkgs[i] = "./" + filepath.Join(pathToInvocationPath, strings.TrimPrefix(coverPkg, "./")) - } else { - // this is a package name - don't touch it - adjustedCoverPkgs[i] = coverPkg - } - } - goFlagsConfig.CoverPkg = strings.Join(adjustedCoverPkgs, ",") - } - - args := []string{"test", "-c", "-o", destination, packageToBuild} - goArgs, err := GenerateFlagArgs( - GoBuildFlags, - map[string]interface{}{ - "Go": &goFlagsConfig, - }, - ) - - if err != nil { - return []string{}, err - } - args = append(args, goArgs...) - return args, nil -} - -// GenerateGinkgoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled Ginkgo test binary -func GenerateGinkgoTestRunArgs(suiteConfig SuiteConfig, reporterConfig ReporterConfig, goFlagsConfig GoFlagsConfig) ([]string, error) { - var flags GinkgoFlags - flags = SuiteConfigFlags.WithPrefix("ginkgo") - flags = flags.CopyAppend(ParallelConfigFlags.WithPrefix("ginkgo")...) - flags = flags.CopyAppend(ReporterConfigFlags.WithPrefix("ginkgo")...) - flags = flags.CopyAppend(GoRunFlags.WithPrefix("test")...) - bindings := map[string]interface{}{ - "S": &suiteConfig, - "R": &reporterConfig, - "Go": &goFlagsConfig, - } - - return GenerateFlagArgs(flags, bindings) -} - -// GenerateGoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled non-Ginkgo test binary -func GenerateGoTestRunArgs(goFlagsConfig GoFlagsConfig) ([]string, error) { - flags := GoRunFlags.WithPrefix("test") - bindings := map[string]interface{}{ - "Go": &goFlagsConfig, - } - - args, err := GenerateFlagArgs(flags, bindings) - if err != nil { - return args, err - } - args = append(args, "--test.v") - return args, nil -} - -// BuildRunCommandFlagSet builds the FlagSet for the `ginkgo run` command -func BuildRunCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig, cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { - flags := SuiteConfigFlags - flags = flags.CopyAppend(ReporterConfigFlags...) - flags = flags.CopyAppend(GinkgoCLISharedFlags...) - flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...) - flags = flags.CopyAppend(GinkgoCLIRunFlags...) - flags = flags.CopyAppend(GoBuildFlags...) - flags = flags.CopyAppend(GoRunFlags...) - - bindings := map[string]interface{}{ - "S": suiteConfig, - "R": reporterConfig, - "C": cliConfig, - "Go": goFlagsConfig, - "D": &deprecatedConfig{}, - } - - return NewGinkgoFlagSet(flags, bindings, FlagSections) -} - -// BuildWatchCommandFlagSet builds the FlagSet for the `ginkgo watch` command -func BuildWatchCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig, cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { - flags := SuiteConfigFlags - flags = flags.CopyAppend(ReporterConfigFlags...) - flags = flags.CopyAppend(GinkgoCLISharedFlags...) - flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...) - flags = flags.CopyAppend(GinkgoCLIWatchFlags...) - flags = flags.CopyAppend(GoBuildFlags...) - flags = flags.CopyAppend(GoRunFlags...) - - bindings := map[string]interface{}{ - "S": suiteConfig, - "R": reporterConfig, - "C": cliConfig, - "Go": goFlagsConfig, - "D": &deprecatedConfig{}, - } - - return NewGinkgoFlagSet(flags, bindings, FlagSections) -} - -// BuildBuildCommandFlagSet builds the FlagSet for the `ginkgo build` command -func BuildBuildCommandFlagSet(cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { - flags := GinkgoCLISharedFlags - flags = flags.CopyAppend(GoBuildFlags...) - - bindings := map[string]interface{}{ - "C": cliConfig, - "Go": goFlagsConfig, - "D": &deprecatedConfig{}, - } - - flagSections := make(GinkgoFlagSections, len(FlagSections)) - copy(flagSections, FlagSections) - for i := range flagSections { - if flagSections[i].Key == "multiple-suites" { - flagSections[i].Heading = "Building Multiple Suites" - } - if flagSections[i].Key == "go-build" { - flagSections[i] = GinkgoFlagSection{Key: "go-build", Style: "{{/}}", Heading: "Go Build Flags", - Description: "These flags are inherited from go build."} - } - } - - return NewGinkgoFlagSet(flags, bindings, flagSections) -} - -func BuildLabelsCommandFlagSet(cliConfig *CLIConfig) (GinkgoFlagSet, error) { - flags := GinkgoCLISharedFlags.SubsetWithNames("r", "skip-package") - - bindings := map[string]interface{}{ - "C": cliConfig, - } - - flagSections := make(GinkgoFlagSections, len(FlagSections)) - copy(flagSections, FlagSections) - for i := range flagSections { - if flagSections[i].Key == "multiple-suites" { - flagSections[i].Heading = "Fetching Labels from Multiple Suites" - } - } - - return NewGinkgoFlagSet(flags, bindings, flagSections) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go b/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go deleted file mode 100644 index 17922304b6..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go +++ /dev/null @@ -1,141 +0,0 @@ -package types - -import ( - "strconv" - "time" -) - -/* - A set of deprecations to make the transition from v1 to v2 easier for users who have written custom reporters. -*/ - -type SuiteSummary = DeprecatedSuiteSummary -type SetupSummary = DeprecatedSetupSummary -type SpecSummary = DeprecatedSpecSummary -type SpecMeasurement = DeprecatedSpecMeasurement -type SpecComponentType = NodeType -type SpecFailure = DeprecatedSpecFailure - -var ( - SpecComponentTypeInvalid = NodeTypeInvalid - SpecComponentTypeContainer = NodeTypeContainer - SpecComponentTypeIt = NodeTypeIt - SpecComponentTypeBeforeEach = NodeTypeBeforeEach - SpecComponentTypeJustBeforeEach = NodeTypeJustBeforeEach - SpecComponentTypeAfterEach = NodeTypeAfterEach - SpecComponentTypeJustAfterEach = NodeTypeJustAfterEach - SpecComponentTypeBeforeSuite = NodeTypeBeforeSuite - SpecComponentTypeSynchronizedBeforeSuite = NodeTypeSynchronizedBeforeSuite - SpecComponentTypeAfterSuite = NodeTypeAfterSuite - SpecComponentTypeSynchronizedAfterSuite = NodeTypeSynchronizedAfterSuite -) - -type DeprecatedSuiteSummary struct { - SuiteDescription string - SuiteSucceeded bool - SuiteID string - - NumberOfSpecsBeforeParallelization int - NumberOfTotalSpecs int - NumberOfSpecsThatWillBeRun int - NumberOfPendingSpecs int - NumberOfSkippedSpecs int - NumberOfPassedSpecs int - NumberOfFailedSpecs int - NumberOfFlakedSpecs int - RunTime time.Duration -} - -type DeprecatedSetupSummary struct { - ComponentType SpecComponentType - CodeLocation CodeLocation - - State SpecState - RunTime time.Duration - Failure SpecFailure - - CapturedOutput string - SuiteID string -} - -type DeprecatedSpecSummary struct { - ComponentTexts []string - ComponentCodeLocations []CodeLocation - - State SpecState - RunTime time.Duration - Failure SpecFailure - IsMeasurement bool - NumberOfSamples int - Measurements map[string]*DeprecatedSpecMeasurement - - CapturedOutput string - SuiteID string -} - -func (s DeprecatedSpecSummary) HasFailureState() bool { - return s.State.Is(SpecStateFailureStates) -} - -func (s DeprecatedSpecSummary) TimedOut() bool { - return false -} - -func (s DeprecatedSpecSummary) Panicked() bool { - return s.State == SpecStatePanicked -} - -func (s DeprecatedSpecSummary) Failed() bool { - return s.State == SpecStateFailed -} - -func (s DeprecatedSpecSummary) Passed() bool { - return s.State == SpecStatePassed -} - -func (s DeprecatedSpecSummary) Skipped() bool { - return s.State == SpecStateSkipped -} - -func (s DeprecatedSpecSummary) Pending() bool { - return s.State == SpecStatePending -} - -type DeprecatedSpecFailure struct { - Message string - Location CodeLocation - ForwardedPanic string - - ComponentIndex int - ComponentType SpecComponentType - ComponentCodeLocation CodeLocation -} - -type DeprecatedSpecMeasurement struct { - Name string - Info interface{} - Order int - - Results []float64 - - Smallest float64 - Largest float64 - Average float64 - StdDeviation float64 - - SmallestLabel string - LargestLabel string - AverageLabel string - Units string - Precision int -} - -func (s DeprecatedSpecMeasurement) PrecisionFmt() string { - if s.Precision == 0 { - return "%f" - } - - str := strconv.Itoa(s.Precision) - - return "%." + str + "f" -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go b/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go deleted file mode 100644 index e2519f673f..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go +++ /dev/null @@ -1,177 +0,0 @@ -package types - -import ( - "os" - "strconv" - "strings" - "sync" - "unicode" - - "github.com/onsi/ginkgo/v2/formatter" -) - -type Deprecation struct { - Message string - DocLink string - Version string -} - -type deprecations struct{} - -var Deprecations = deprecations{} - -func (d deprecations) CustomReporter() Deprecation { - return Deprecation{ - Message: "Support for custom reporters has been removed in V2. Please read the documentation linked to below for Ginkgo's new behavior and for a migration path:", - DocLink: "removed-custom-reporters", - Version: "1.16.0", - } -} - -func (d deprecations) Async() Deprecation { - return Deprecation{ - Message: "You are passing a Done channel to a test node to test asynchronous behavior. This is deprecated in Ginkgo V2. Your test will run synchronously and the timeout will be ignored.", - DocLink: "removed-async-testing", - Version: "1.16.0", - } -} - -func (d deprecations) Measure() Deprecation { - return Deprecation{ - Message: "Measure is deprecated and has been removed from Ginkgo V2. Any Measure tests in your spec will not run. Please migrate to gomega/gmeasure.", - DocLink: "removed-measure", - Version: "1.16.3", - } -} - -func (d deprecations) ParallelNode() Deprecation { - return Deprecation{ - Message: "GinkgoParallelNode is deprecated and will be removed in Ginkgo V2. Please use GinkgoParallelProcess instead.", - DocLink: "renamed-ginkgoparallelnode", - Version: "1.16.4", - } -} - -func (d deprecations) CurrentGinkgoTestDescription() Deprecation { - return Deprecation{ - Message: "CurrentGinkgoTestDescription() is deprecated in Ginkgo V2. Use CurrentSpecReport() instead.", - DocLink: "changed-currentginkgotestdescription", - Version: "1.16.0", - } -} - -func (d deprecations) Convert() Deprecation { - return Deprecation{ - Message: "The convert command is deprecated in Ginkgo V2", - DocLink: "removed-ginkgo-convert", - Version: "1.16.0", - } -} - -func (d deprecations) Blur() Deprecation { - return Deprecation{ - Message: "The blur command is deprecated in Ginkgo V2. Use 'ginkgo unfocus' instead.", - Version: "1.16.0", - } -} - -func (d deprecations) Nodot() Deprecation { - return Deprecation{ - Message: "The nodot command is deprecated in Ginkgo V2. Please either dot-import Ginkgo or use the package identifier in your code to references objects and types provided by Ginkgo and Gomega.", - DocLink: "removed-ginkgo-nodot", - Version: "1.16.0", - } -} - -func (d deprecations) SuppressProgressReporting() Deprecation { - return Deprecation{ - Message: "Improvements to how reporters emit timeline information means that SuppressProgressReporting is no longer necessary and has been deprecated.", - Version: "2.5.0", - } -} - -type DeprecationTracker struct { - deprecations map[Deprecation][]CodeLocation - lock *sync.Mutex -} - -func NewDeprecationTracker() *DeprecationTracker { - return &DeprecationTracker{ - deprecations: map[Deprecation][]CodeLocation{}, - lock: &sync.Mutex{}, - } -} - -func (d *DeprecationTracker) TrackDeprecation(deprecation Deprecation, cl ...CodeLocation) { - ackVersion := os.Getenv("ACK_GINKGO_DEPRECATIONS") - if deprecation.Version != "" && ackVersion != "" { - ack := ParseSemVer(ackVersion) - version := ParseSemVer(deprecation.Version) - if ack.GreaterThanOrEqualTo(version) { - return - } - } - - d.lock.Lock() - defer d.lock.Unlock() - if len(cl) == 1 { - d.deprecations[deprecation] = append(d.deprecations[deprecation], cl[0]) - } else { - d.deprecations[deprecation] = []CodeLocation{} - } -} - -func (d *DeprecationTracker) DidTrackDeprecations() bool { - d.lock.Lock() - defer d.lock.Unlock() - return len(d.deprecations) > 0 -} - -func (d *DeprecationTracker) DeprecationsReport() string { - d.lock.Lock() - defer d.lock.Unlock() - out := formatter.F("{{light-yellow}}You're using deprecated Ginkgo functionality:{{/}}\n") - out += formatter.F("{{light-yellow}}============================================={{/}}\n") - for deprecation, locations := range d.deprecations { - out += formatter.Fi(1, "{{yellow}}"+deprecation.Message+"{{/}}\n") - if deprecation.DocLink != "" { - out += formatter.Fi(1, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}https://onsi.github.io/ginkgo/MIGRATING_TO_V2#%s{{/}}\n", deprecation.DocLink) - } - for _, location := range locations { - out += formatter.Fi(2, "{{gray}}%s{{/}}\n", location) - } - } - out += formatter.F("\n{{gray}}To silence deprecations that can be silenced set the following environment variable:{{/}}\n") - out += formatter.Fi(1, "{{gray}}ACK_GINKGO_DEPRECATIONS=%s{{/}}\n", VERSION) - return out -} - -type SemVer struct { - Major int - Minor int - Patch int -} - -func (s SemVer) GreaterThanOrEqualTo(o SemVer) bool { - return (s.Major > o.Major) || - (s.Major == o.Major && s.Minor > o.Minor) || - (s.Major == o.Major && s.Minor == o.Minor && s.Patch >= o.Patch) -} - -func ParseSemVer(semver string) SemVer { - out := SemVer{} - semver = strings.TrimFunc(semver, func(r rune) bool { - return !(unicode.IsNumber(r) || r == '.') - }) - components := strings.Split(semver, ".") - if len(components) > 0 { - out.Major, _ = strconv.Atoi(components[0]) - } - if len(components) > 1 { - out.Minor, _ = strconv.Atoi(components[1]) - } - if len(components) > 2 { - out.Patch, _ = strconv.Atoi(components[2]) - } - return out -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go b/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go deleted file mode 100644 index 1d96ae0280..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go +++ /dev/null @@ -1,43 +0,0 @@ -package types - -import "encoding/json" - -type EnumSupport struct { - toString map[uint]string - toEnum map[string]uint - maxEnum uint -} - -func NewEnumSupport(toString map[uint]string) EnumSupport { - toEnum, maxEnum := map[string]uint{}, uint(0) - for k, v := range toString { - toEnum[v] = k - if maxEnum < k { - maxEnum = k - } - } - return EnumSupport{toString: toString, toEnum: toEnum, maxEnum: maxEnum} -} - -func (es EnumSupport) String(e uint) string { - if e > es.maxEnum { - return es.toString[0] - } - return es.toString[e] -} - -func (es EnumSupport) UnmarshJSON(b []byte) (uint, error) { - var dec string - if err := json.Unmarshal(b, &dec); err != nil { - return 0, err - } - out := es.toEnum[dec] // if we miss we get 0 which is what we want anyway - return out, nil -} - -func (es EnumSupport) MarshJSON(e uint) ([]byte, error) { - if e == 0 || e > es.maxEnum { - return json.Marshal(nil) - } - return json.Marshal(es.toString[e]) -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/errors.go b/vendor/github.com/onsi/ginkgo/v2/types/errors.go deleted file mode 100644 index 1e0dbfd9df..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/errors.go +++ /dev/null @@ -1,630 +0,0 @@ -package types - -import ( - "fmt" - "reflect" - "strings" - - "github.com/onsi/ginkgo/v2/formatter" -) - -type GinkgoError struct { - Heading string - Message string - DocLink string - CodeLocation CodeLocation -} - -func (g GinkgoError) Error() string { - out := formatter.F("{{bold}}{{red}}%s{{/}}\n", g.Heading) - if (g.CodeLocation != CodeLocation{}) { - contentsOfLine := strings.TrimLeft(g.CodeLocation.ContentsOfLine(), "\t ") - if contentsOfLine != "" { - out += formatter.F("{{light-gray}}%s{{/}}\n", contentsOfLine) - } - out += formatter.F("{{gray}}%s{{/}}\n", g.CodeLocation) - } - if g.Message != "" { - out += formatter.Fiw(1, formatter.COLS, g.Message) - out += "\n\n" - } - if g.DocLink != "" { - out += formatter.Fiw(1, formatter.COLS, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}http://onsi.github.io/ginkgo/#%s{{/}}\n", g.DocLink) - } - - return out -} - -type ginkgoErrors struct{} - -var GinkgoErrors = ginkgoErrors{} - -func (g ginkgoErrors) UncaughtGinkgoPanic(cl CodeLocation) error { - return GinkgoError{ - Heading: "Your Test Panicked", - Message: `When you, or your assertion library, calls Ginkgo's Fail(), -Ginkgo panics to prevent subsequent assertions from running. - -Normally Ginkgo rescues this panic so you shouldn't see it. - -However, if you make an assertion in a goroutine, Ginkgo can't capture the panic. -To circumvent this, you should call - - defer GinkgoRecover() - -at the top of the goroutine that caused this panic. - -Alternatively, you may have made an assertion outside of a Ginkgo -leaf node (e.g. in a container node or some out-of-band function) - please move your assertion to -an appropriate Ginkgo node (e.g. a BeforeSuite, BeforeEach, It, etc...).`, - DocLink: "mental-model-how-ginkgo-handles-failure", - CodeLocation: cl, - } -} - -func (g ginkgoErrors) RerunningSuite() error { - return GinkgoError{ - Heading: "Rerunning Suite", - Message: formatter.F(`It looks like you are calling RunSpecs more than once. Ginkgo does not support rerunning suites. If you want to rerun a suite try {{bold}}ginkgo --repeat=N{{/}} or {{bold}}ginkgo --until-it-fails{{/}}`), - DocLink: "repeating-spec-runs-and-managing-flaky-specs", - } -} - -/* Tree construction errors */ - -func (g ginkgoErrors) PushingNodeInRunPhase(nodeType NodeType, cl CodeLocation) error { - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F( - `It looks like you are trying to add a {{bold}}[%s]{{/}} node -to the Ginkgo spec tree in a leaf node {{bold}}after{{/}} the specs started running. - -To enable randomization and parallelization Ginkgo requires the spec tree -to be fully constructed up front. In practice, this means that you can -only create nodes like {{bold}}[%s]{{/}} at the top-level or within the -body of a {{bold}}Describe{{/}}, {{bold}}Context{{/}}, or {{bold}}When{{/}}.`, nodeType, nodeType), - CodeLocation: cl, - DocLink: "mental-model-how-ginkgo-traverses-the-spec-hierarchy", - } -} - -func (g ginkgoErrors) CaughtPanicDuringABuildPhase(caughtPanic interface{}, cl CodeLocation) error { - return GinkgoError{ - Heading: "Assertion or Panic detected during tree construction", - Message: formatter.F( - `Ginkgo detected a panic while constructing the spec tree. -You may be trying to make an assertion in the body of a container node -(i.e. {{bold}}Describe{{/}}, {{bold}}Context{{/}}, or {{bold}}When{{/}}). - -Please ensure all assertions are inside leaf nodes such as {{bold}}BeforeEach{{/}}, -{{bold}}It{{/}}, etc. - -{{bold}}Here's the content of the panic that was caught:{{/}} -%v`, caughtPanic), - CodeLocation: cl, - DocLink: "no-assertions-in-container-nodes", - } -} - -func (g ginkgoErrors) SuiteNodeInNestedContext(nodeType NodeType, cl CodeLocation) error { - docLink := "suite-setup-and-cleanup-beforesuite-and-aftersuite" - if nodeType.Is(NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite) { - docLink = "reporting-nodes---reportbeforesuite-and-reportaftersuite" - } - - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F( - `It looks like you are trying to add a {{bold}}[%s]{{/}} node within a container node. - -{{bold}}%s{{/}} can only be called at the top level.`, nodeType, nodeType), - CodeLocation: cl, - DocLink: docLink, - } -} - -func (g ginkgoErrors) SuiteNodeDuringRunPhase(nodeType NodeType, cl CodeLocation) error { - docLink := "suite-setup-and-cleanup-beforesuite-and-aftersuite" - if nodeType.Is(NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite) { - docLink = "reporting-nodes---reportbeforesuite-and-reportaftersuite" - } - - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F( - `It looks like you are trying to add a {{bold}}[%s]{{/}} node within a leaf node after the spec started running. - -{{bold}}%s{{/}} can only be called at the top level.`, nodeType, nodeType), - CodeLocation: cl, - DocLink: docLink, - } -} - -func (g ginkgoErrors) MultipleBeforeSuiteNodes(nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { - return ginkgoErrorMultipleSuiteNodes("setup", nodeType, cl, earlierNodeType, earlierCodeLocation) -} - -func (g ginkgoErrors) MultipleAfterSuiteNodes(nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { - return ginkgoErrorMultipleSuiteNodes("teardown", nodeType, cl, earlierNodeType, earlierCodeLocation) -} - -func ginkgoErrorMultipleSuiteNodes(setupOrTeardown string, nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F( - `It looks like you are trying to add a {{bold}}[%s]{{/}} node but -you already have a {{bold}}[%s]{{/}} node defined at: {{gray}}%s{{/}}. - -Ginkgo only allows you to define one suite %s node.`, nodeType, earlierNodeType, earlierCodeLocation, setupOrTeardown), - CodeLocation: cl, - DocLink: "suite-setup-and-cleanup-beforesuite-and-aftersuite", - } -} - -/* Decorator errors */ -func (g ginkgoErrors) InvalidDecoratorForNodeType(cl CodeLocation, nodeType NodeType, decorator string) error { - return GinkgoError{ - Heading: "Invalid Decorator", - Message: formatter.F(`[%s] node cannot be passed a(n) '%s' decorator`, nodeType, decorator), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidDeclarationOfFocusedAndPending(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Invalid Combination of Decorators: Focused and Pending", - Message: formatter.F(`[%s] node was decorated with both Focus and Pending. At most one is allowed.`, nodeType), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidDeclarationOfFlakeAttemptsAndMustPassRepeatedly(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Invalid Combination of Decorators: FlakeAttempts and MustPassRepeatedly", - Message: formatter.F(`[%s] node was decorated with both FlakeAttempts and MustPassRepeatedly. At most one is allowed.`, nodeType), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) UnknownDecorator(cl CodeLocation, nodeType NodeType, decorator interface{}) error { - return GinkgoError{ - Heading: "Unknown Decorator", - Message: formatter.F(`[%s] node was passed an unknown decorator: '%#v'`, nodeType, decorator), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidBodyTypeForContainer(t reflect.Type, cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Invalid Function", - Message: formatter.F(`[%s] node must be passed {{bold}}func(){{/}} - i.e. functions that take nothing and return nothing. You passed {{bold}}%s{{/}} instead.`, nodeType, t), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidBodyType(t reflect.Type, cl CodeLocation, nodeType NodeType) error { - mustGet := "{{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}" - if nodeType.Is(NodeTypeContainer) { - mustGet = "{{bold}}func(){{/}}" - } - return GinkgoError{ - Heading: "Invalid Function", - Message: formatter.F(`[%s] node must be passed `+mustGet+`. -You passed {{bold}}%s{{/}} instead.`, nodeType, t), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidBodyTypeForSynchronizedBeforeSuiteProc1(t reflect.Type, cl CodeLocation) error { - mustGet := "{{bold}}func() []byte{{/}}, {{bold}}func(ctx SpecContext) []byte{{/}}, or {{bold}}func(ctx context.Context) []byte{{/}}, {{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}" - return GinkgoError{ - Heading: "Invalid Function", - Message: formatter.F(`[SynchronizedBeforeSuite] node must be passed `+mustGet+` for its first function. -You passed {{bold}}%s{{/}} instead.`, t), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidBodyTypeForSynchronizedBeforeSuiteAllProcs(t reflect.Type, cl CodeLocation) error { - mustGet := "{{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}, {{bold}}func([]byte){{/}}, {{bold}}func(ctx SpecContext, []byte){{/}}, or {{bold}}func(ctx context.Context, []byte){{/}}" - return GinkgoError{ - Heading: "Invalid Function", - Message: formatter.F(`[SynchronizedBeforeSuite] node must be passed `+mustGet+` for its second function. -You passed {{bold}}%s{{/}} instead.`, t), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) MultipleBodyFunctions(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Multiple Functions", - Message: formatter.F(`[%s] node must be passed a single function - but more than one was passed in.`, nodeType), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) MissingBodyFunction(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Missing Functions", - Message: formatter.F(`[%s] node must be passed a single function - but none was passed in.`, nodeType), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) InvalidTimeoutOrGracePeriodForNonContextNode(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Invalid NodeTimeout SpecTimeout, or GracePeriod", - Message: formatter.F(`[%s] was passed NodeTimeout, SpecTimeout, or GracePeriod but does not have a callback that accepts a {{bold}}SpecContext{{/}} or {{bold}}context.Context{{/}}. You must accept a context to enable timeouts and grace periods`, nodeType), - CodeLocation: cl, - DocLink: "spec-timeouts-and-interruptible-nodes", - } -} - -func (g ginkgoErrors) InvalidTimeoutOrGracePeriodForNonContextCleanupNode(cl CodeLocation) error { - return GinkgoError{ - Heading: "Invalid NodeTimeout SpecTimeout, or GracePeriod", - Message: formatter.F(`[DeferCleanup] was passed NodeTimeout or GracePeriod but does not have a callback that accepts a {{bold}}SpecContext{{/}} or {{bold}}context.Context{{/}}. You must accept a context to enable timeouts and grace periods`), - CodeLocation: cl, - DocLink: "spec-timeouts-and-interruptible-nodes", - } -} - -/* Ordered Container errors */ -func (g ginkgoErrors) InvalidSerialNodeInNonSerialOrderedContainer(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Invalid Serial Node in Non-Serial Ordered Container", - Message: formatter.F(`[%s] node was decorated with Serial but occurs in an Ordered container that is not marked Serial. Move the Serial decorator to the outer-most Ordered container to mark all ordered specs within the container as serial.`, nodeType), - CodeLocation: cl, - DocLink: "node-decorators-overview", - } -} - -func (g ginkgoErrors) SetupNodeNotInOrderedContainer(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: "Setup Node not in Ordered Container", - Message: fmt.Sprintf("[%s] setup nodes must appear inside an Ordered container. They cannot be nested within other containers, even containers in an ordered container.", nodeType), - CodeLocation: cl, - DocLink: "ordered-containers", - } -} - -func (g ginkgoErrors) InvalidContinueOnFailureDecoration(cl CodeLocation) error { - return GinkgoError{ - Heading: "ContinueOnFailure not decorating an outermost Ordered Container", - Message: "ContinueOnFailure can only decorate an Ordered container, and this Ordered container must be the outermost Ordered container.", - CodeLocation: cl, - DocLink: "ordered-containers", - } -} - -/* DeferCleanup errors */ -func (g ginkgoErrors) DeferCleanupInvalidFunction(cl CodeLocation) error { - return GinkgoError{ - Heading: "DeferCleanup requires a valid function", - Message: "You must pass DeferCleanup a function to invoke. This function must return zero or one values - if it does return, it must return an error. The function can take arbitrarily many arguments and you should provide these to DeferCleanup to pass along to the function.", - CodeLocation: cl, - DocLink: "cleaning-up-our-cleanup-code-defercleanup", - } -} - -func (g ginkgoErrors) PushingCleanupNodeDuringTreeConstruction(cl CodeLocation) error { - return GinkgoError{ - Heading: "DeferCleanup must be called inside a setup or subject node", - Message: "You must call DeferCleanup inside a setup node (e.g. BeforeEach, BeforeSuite, AfterAll...) or a subject node (i.e. It). You can't call DeferCleanup at the top-level or in a container node - use the After* family of setup nodes instead.", - CodeLocation: cl, - DocLink: "cleaning-up-our-cleanup-code-defercleanup", - } -} - -func (g ginkgoErrors) PushingCleanupInReportingNode(cl CodeLocation, nodeType NodeType) error { - return GinkgoError{ - Heading: fmt.Sprintf("DeferCleanup cannot be called in %s", nodeType), - Message: "Please inline your cleanup code - Ginkgo won't run cleanup code after a Reporting node.", - CodeLocation: cl, - DocLink: "cleaning-up-our-cleanup-code-defercleanup", - } -} - -func (g ginkgoErrors) PushingCleanupInCleanupNode(cl CodeLocation) error { - return GinkgoError{ - Heading: "DeferCleanup cannot be called in a DeferCleanup callback", - Message: "Please inline your cleanup code - Ginkgo doesn't let you call DeferCleanup from within DeferCleanup", - CodeLocation: cl, - DocLink: "cleaning-up-our-cleanup-code-defercleanup", - } -} - -/* ReportEntry errors */ -func (g ginkgoErrors) TooManyReportEntryValues(cl CodeLocation, arg interface{}) error { - return GinkgoError{ - Heading: "Too Many ReportEntry Values", - Message: formatter.F(`{{bold}}AddGinkgoReport{{/}} can only be given one value. Got unexpected value: %#v`, arg), - CodeLocation: cl, - DocLink: "attaching-data-to-reports", - } -} - -func (g ginkgoErrors) AddReportEntryNotDuringRunPhase(cl CodeLocation) error { - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F(`It looks like you are calling {{bold}}AddGinkgoReport{{/}} outside of a running spec. Make sure you call {{bold}}AddGinkgoReport{{/}} inside a runnable node such as It or BeforeEach and not inside the body of a container such as Describe or Context.`), - CodeLocation: cl, - DocLink: "attaching-data-to-reports", - } -} - -/* By errors */ -func (g ginkgoErrors) ByNotDuringRunPhase(cl CodeLocation) error { - return GinkgoError{ - Heading: "Ginkgo detected an issue with your spec structure", - Message: formatter.F(`It looks like you are calling {{bold}}By{{/}} outside of a running spec. Make sure you call {{bold}}By{{/}} inside a runnable node such as It or BeforeEach and not inside the body of a container such as Describe or Context.`), - CodeLocation: cl, - DocLink: "documenting-complex-specs-by", - } -} - -/* FileFilter and SkipFilter errors */ -func (g ginkgoErrors) InvalidFileFilter(filter string) error { - return GinkgoError{ - Heading: "Invalid File Filter", - Message: fmt.Sprintf(`The provided file filter: "%s" is invalid. File filters must have the format "file", "file:lines" where "file" is a regular expression that will match against the file path and lines is a comma-separated list of integers (e.g. file:1,5,7) or line-ranges (e.g. file:1-3,5-9) or both (e.g. file:1,5-9)`, filter), - DocLink: "filtering-specs", - } -} - -func (g ginkgoErrors) InvalidFileFilterRegularExpression(filter string, err error) error { - return GinkgoError{ - Heading: "Invalid File Filter Regular Expression", - Message: fmt.Sprintf(`The provided file filter: "%s" included an invalid regular expression. regexp.Compile error: %s`, filter, err), - DocLink: "filtering-specs", - } -} - -/* Label Errors */ -func (g ginkgoErrors) SyntaxErrorParsingLabelFilter(input string, location int, error string) error { - var message string - if location >= 0 { - for i, r := range input { - if i == location { - message += "{{red}}{{bold}}{{underline}}" - } - message += string(r) - if i == location { - message += "{{/}}" - } - } - } else { - message = input - } - message += "\n" + error - return GinkgoError{ - Heading: "Syntax Error Parsing Label Filter", - Message: message, - DocLink: "spec-labels", - } -} - -func (g ginkgoErrors) InvalidLabel(label string, cl CodeLocation) error { - return GinkgoError{ - Heading: "Invalid Label", - Message: fmt.Sprintf("'%s' is an invalid label. Labels cannot contain of the following characters: '&|!,()/'", label), - CodeLocation: cl, - DocLink: "spec-labels", - } -} - -func (g ginkgoErrors) InvalidEmptyLabel(cl CodeLocation) error { - return GinkgoError{ - Heading: "Invalid Empty Label", - Message: "Labels cannot be empty", - CodeLocation: cl, - DocLink: "spec-labels", - } -} - -/* Table errors */ -func (g ginkgoErrors) MultipleEntryBodyFunctionsForTable(cl CodeLocation) error { - return GinkgoError{ - Heading: "DescribeTable passed multiple functions", - Message: "It looks like you are passing multiple functions into DescribeTable. Only one function can be passed in. This function will be called for each Entry in the table.", - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) InvalidEntryDescription(cl CodeLocation) error { - return GinkgoError{ - Heading: "Invalid Entry description", - Message: "Entry description functions must be a string, a function that accepts the entry parameters and returns a string, or nil.", - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) MissingParametersForTableFunction(cl CodeLocation) error { - return GinkgoError{ - Heading: fmt.Sprintf("No parameters have been passed to the Table Function"), - Message: fmt.Sprintf("The Table Function expected at least 1 parameter"), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) IncorrectParameterTypeForTable(i int, name string, cl CodeLocation) error { - return GinkgoError{ - Heading: "DescribeTable passed incorrect parameter type", - Message: fmt.Sprintf("Parameter #%d passed to DescribeTable is of incorrect type <%s>", i, name), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) TooFewParametersToTableFunction(expected, actual int, kind string, cl CodeLocation) error { - return GinkgoError{ - Heading: fmt.Sprintf("Too few parameters passed in to %s", kind), - Message: fmt.Sprintf("The %s expected %d parameters but you passed in %d", kind, expected, actual), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) TooManyParametersToTableFunction(expected, actual int, kind string, cl CodeLocation) error { - return GinkgoError{ - Heading: fmt.Sprintf("Too many parameters passed in to %s", kind), - Message: fmt.Sprintf("The %s expected %d parameters but you passed in %d", kind, expected, actual), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) IncorrectParameterTypeToTableFunction(i int, expected, actual reflect.Type, kind string, cl CodeLocation) error { - return GinkgoError{ - Heading: fmt.Sprintf("Incorrect parameters type passed to %s", kind), - Message: fmt.Sprintf("The %s expected parameter #%d to be of type <%s> but you passed in <%s>", kind, i, expected, actual), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -func (g ginkgoErrors) IncorrectVariadicParameterTypeToTableFunction(expected, actual reflect.Type, kind string, cl CodeLocation) error { - return GinkgoError{ - Heading: fmt.Sprintf("Incorrect parameters type passed to %s", kind), - Message: fmt.Sprintf("The %s expected its variadic parameters to be of type <%s> but you passed in <%s>", kind, expected, actual), - CodeLocation: cl, - DocLink: "table-specs", - } -} - -/* Parallel Synchronization errors */ - -func (g ginkgoErrors) AggregatedReportUnavailableDueToNodeDisappearing() error { - return GinkgoError{ - Heading: "Test Report unavailable because a Ginkgo parallel process disappeared", - Message: "The aggregated report could not be fetched for a ReportAfterSuite node. A Ginkgo parallel process disappeared before it could finish reporting.", - } -} - -func (g ginkgoErrors) SynchronizedBeforeSuiteFailedOnProc1() error { - return GinkgoError{ - Heading: "SynchronizedBeforeSuite failed on Ginkgo parallel process #1", - Message: "The first SynchronizedBeforeSuite function running on Ginkgo parallel process #1 failed. This suite will now abort.", - } -} - -func (g ginkgoErrors) SynchronizedBeforeSuiteDisappearedOnProc1() error { - return GinkgoError{ - Heading: "Process #1 disappeared before SynchronizedBeforeSuite could report back", - Message: "Ginkgo parallel process #1 disappeared before the first SynchronizedBeforeSuite function completed. This suite will now abort.", - } -} - -/* Configuration errors */ - -func (g ginkgoErrors) UnknownTypePassedToRunSpecs(value interface{}) error { - return GinkgoError{ - Heading: "Unknown Type passed to RunSpecs", - Message: fmt.Sprintf("RunSpecs() accepts labels, and configuration of type types.SuiteConfig and/or types.ReporterConfig.\n You passed in: %v", value), - } -} - -var sharedParallelErrorMessage = "It looks like you are trying to run specs in parallel with go test.\nThis is unsupported and you should use the ginkgo CLI instead." - -func (g ginkgoErrors) InvalidParallelTotalConfiguration() error { - return GinkgoError{ - Heading: "-ginkgo.parallel.total must be >= 1", - Message: sharedParallelErrorMessage, - DocLink: "spec-parallelization", - } -} - -func (g ginkgoErrors) InvalidParallelProcessConfiguration() error { - return GinkgoError{ - Heading: "-ginkgo.parallel.process is one-indexed and must be <= ginkgo.parallel.total", - Message: sharedParallelErrorMessage, - DocLink: "spec-parallelization", - } -} - -func (g ginkgoErrors) MissingParallelHostConfiguration() error { - return GinkgoError{ - Heading: "-ginkgo.parallel.host is missing", - Message: sharedParallelErrorMessage, - DocLink: "spec-parallelization", - } -} - -func (g ginkgoErrors) UnreachableParallelHost(host string) error { - return GinkgoError{ - Heading: "Could not reach ginkgo.parallel.host:" + host, - Message: sharedParallelErrorMessage, - DocLink: "spec-parallelization", - } -} - -func (g ginkgoErrors) DryRunInParallelConfiguration() error { - return GinkgoError{ - Heading: "Ginkgo only performs -dryRun in serial mode.", - Message: "Please try running ginkgo -dryRun again, but without -p or -procs to ensure the suite is running in series.", - } -} - -func (g ginkgoErrors) GracePeriodCannotBeZero() error { - return GinkgoError{ - Heading: "Ginkgo requires a positive --grace-period.", - Message: "Please set --grace-period to a positive duration. The default is 30s.", - } -} - -func (g ginkgoErrors) ConflictingVerbosityConfiguration() error { - return GinkgoError{ - Heading: "Conflicting reporter verbosity settings.", - Message: "You can't set more than one of -v, -vv and --succinct. Please pick one!", - } -} - -func (g ginkgoErrors) InvalidOutputInterceptorModeConfiguration(value string) error { - return GinkgoError{ - Heading: fmt.Sprintf("Invalid value '%s' for --output-interceptor-mode.", value), - Message: "You must choose one of 'dup', 'swap', or 'none'.", - } -} - -func (g ginkgoErrors) InvalidGoFlagCount() error { - return GinkgoError{ - Heading: "Use of go test -count", - Message: "Ginkgo does not support using go test -count to rerun suites. Only -count=1 is allowed. To repeat suite runs, please use the ginkgo cli and `ginkgo -until-it-fails` or `ginkgo -repeat=N`.", - } -} - -func (g ginkgoErrors) InvalidGoFlagParallel() error { - return GinkgoError{ - Heading: "Use of go test -parallel", - Message: "Go test's implementation of parallelization does not actually parallelize Ginkgo specs. Please use the ginkgo cli and `ginkgo -p` or `ginkgo -procs=N` instead.", - } -} - -func (g ginkgoErrors) BothRepeatAndUntilItFails() error { - return GinkgoError{ - Heading: "--repeat and --until-it-fails are both set", - Message: "--until-it-fails directs Ginkgo to rerun specs indefinitely until they fail. --repeat directs Ginkgo to rerun specs a set number of times. You can't set both... which would you like?", - } -} - -/* Stack-Trace parsing errors */ - -func (g ginkgoErrors) FailedToParseStackTrace(message string) error { - return GinkgoError{ - Heading: "Failed to Parse Stack Trace", - Message: message, - } -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go b/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go deleted file mode 100644 index cc21df71ec..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go +++ /dev/null @@ -1,106 +0,0 @@ -package types - -import ( - "regexp" - "strconv" - "strings" -) - -func ParseFileFilters(filters []string) (FileFilters, error) { - ffs := FileFilters{} - for _, filter := range filters { - ff := FileFilter{} - if filter == "" { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - components := strings.Split(filter, ":") - if !(len(components) == 1 || len(components) == 2) { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - - var err error - ff.Filename, err = regexp.Compile(components[0]) - if err != nil { - return nil, err - } - if len(components) == 2 { - lineFilters := strings.Split(components[1], ",") - for _, lineFilter := range lineFilters { - components := strings.Split(lineFilter, "-") - if len(components) == 1 { - line, err := strconv.Atoi(strings.TrimSpace(components[0])) - if err != nil { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - ff.LineFilters = append(ff.LineFilters, LineFilter{line, line + 1}) - } else if len(components) == 2 { - line1, err := strconv.Atoi(strings.TrimSpace(components[0])) - if err != nil { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - line2, err := strconv.Atoi(strings.TrimSpace(components[1])) - if err != nil { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - ff.LineFilters = append(ff.LineFilters, LineFilter{line1, line2}) - } else { - return nil, GinkgoErrors.InvalidFileFilter(filter) - } - } - } - ffs = append(ffs, ff) - } - return ffs, nil -} - -type FileFilter struct { - Filename *regexp.Regexp - LineFilters LineFilters -} - -func (f FileFilter) Matches(locations []CodeLocation) bool { - for _, location := range locations { - if f.Filename.MatchString(location.FileName) && - f.LineFilters.Matches(location.LineNumber) { - return true - } - - } - return false -} - -type FileFilters []FileFilter - -func (ffs FileFilters) Matches(locations []CodeLocation) bool { - for _, ff := range ffs { - if ff.Matches(locations) { - return true - } - } - - return false -} - -type LineFilter struct { - Min int - Max int -} - -func (lf LineFilter) Matches(line int) bool { - return lf.Min <= line && line < lf.Max -} - -type LineFilters []LineFilter - -func (lfs LineFilters) Matches(line int) bool { - if len(lfs) == 0 { - return true - } - - for _, lf := range lfs { - if lf.Matches(line) { - return true - } - } - return false -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/flags.go b/vendor/github.com/onsi/ginkgo/v2/types/flags.go deleted file mode 100644 index 9186ae873d..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/flags.go +++ /dev/null @@ -1,489 +0,0 @@ -package types - -import ( - "flag" - "fmt" - "io" - "reflect" - "strings" - "time" - - "github.com/onsi/ginkgo/v2/formatter" -) - -type GinkgoFlag struct { - Name string - KeyPath string - SectionKey string - - Usage string - UsageArgument string - UsageDefaultValue string - - DeprecatedName string - DeprecatedDocLink string - DeprecatedVersion string - - ExportAs string -} - -type GinkgoFlags []GinkgoFlag - -func (f GinkgoFlags) CopyAppend(flags ...GinkgoFlag) GinkgoFlags { - out := GinkgoFlags{} - out = append(out, f...) - out = append(out, flags...) - return out -} - -func (f GinkgoFlags) WithPrefix(prefix string) GinkgoFlags { - if prefix == "" { - return f - } - out := GinkgoFlags{} - for _, flag := range f { - if flag.Name != "" { - flag.Name = prefix + "." + flag.Name - } - if flag.DeprecatedName != "" { - flag.DeprecatedName = prefix + "." + flag.DeprecatedName - } - if flag.ExportAs != "" { - flag.ExportAs = prefix + "." + flag.ExportAs - } - out = append(out, flag) - } - return out -} - -func (f GinkgoFlags) SubsetWithNames(names ...string) GinkgoFlags { - out := GinkgoFlags{} - for _, flag := range f { - for _, name := range names { - if flag.Name == name { - out = append(out, flag) - break - } - } - } - return out -} - -type GinkgoFlagSection struct { - Key string - Style string - Succinct bool - Heading string - Description string -} - -type GinkgoFlagSections []GinkgoFlagSection - -func (gfs GinkgoFlagSections) Lookup(key string) (GinkgoFlagSection, bool) { - for _, section := range gfs { - if section.Key == key { - return section, true - } - } - - return GinkgoFlagSection{}, false -} - -type GinkgoFlagSet struct { - flags GinkgoFlags - bindings interface{} - - sections GinkgoFlagSections - extraGoFlagsSection GinkgoFlagSection - - flagSet *flag.FlagSet -} - -// Call NewGinkgoFlagSet to create GinkgoFlagSet that creates and binds to it's own *flag.FlagSet -func NewGinkgoFlagSet(flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections) (GinkgoFlagSet, error) { - return bindFlagSet(GinkgoFlagSet{ - flags: flags, - bindings: bindings, - sections: sections, - }, nil) -} - -// Call NewGinkgoFlagSet to create GinkgoFlagSet that extends an existing *flag.FlagSet -func NewAttachedGinkgoFlagSet(flagSet *flag.FlagSet, flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections, extraGoFlagsSection GinkgoFlagSection) (GinkgoFlagSet, error) { - return bindFlagSet(GinkgoFlagSet{ - flags: flags, - bindings: bindings, - sections: sections, - extraGoFlagsSection: extraGoFlagsSection, - }, flagSet) -} - -func bindFlagSet(f GinkgoFlagSet, flagSet *flag.FlagSet) (GinkgoFlagSet, error) { - if flagSet == nil { - f.flagSet = flag.NewFlagSet("", flag.ContinueOnError) - //suppress all output as Ginkgo is responsible for formatting usage - f.flagSet.SetOutput(io.Discard) - } else { - f.flagSet = flagSet - //we're piggybacking on an existing flagset (typically go test) so we have limited control - //on user feedback - f.flagSet.Usage = f.substituteUsage - } - - for _, flag := range f.flags { - name := flag.Name - - deprecatedUsage := "[DEPRECATED]" - deprecatedName := flag.DeprecatedName - if name != "" { - deprecatedUsage = fmt.Sprintf("[DEPRECATED] use --%s instead", name) - } else if flag.Usage != "" { - deprecatedUsage += " " + flag.Usage - } - - value, ok := valueAtKeyPath(f.bindings, flag.KeyPath) - if !ok { - return GinkgoFlagSet{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath) - } - - iface, addr := value.Interface(), value.Addr().Interface() - - switch value.Type() { - case reflect.TypeOf(string("")): - if name != "" { - f.flagSet.StringVar(addr.(*string), name, iface.(string), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.StringVar(addr.(*string), deprecatedName, iface.(string), deprecatedUsage) - } - case reflect.TypeOf(int64(0)): - if name != "" { - f.flagSet.Int64Var(addr.(*int64), name, iface.(int64), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.Int64Var(addr.(*int64), deprecatedName, iface.(int64), deprecatedUsage) - } - case reflect.TypeOf(float64(0)): - if name != "" { - f.flagSet.Float64Var(addr.(*float64), name, iface.(float64), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.Float64Var(addr.(*float64), deprecatedName, iface.(float64), deprecatedUsage) - } - case reflect.TypeOf(int(0)): - if name != "" { - f.flagSet.IntVar(addr.(*int), name, iface.(int), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.IntVar(addr.(*int), deprecatedName, iface.(int), deprecatedUsage) - } - case reflect.TypeOf(bool(true)): - if name != "" { - f.flagSet.BoolVar(addr.(*bool), name, iface.(bool), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.BoolVar(addr.(*bool), deprecatedName, iface.(bool), deprecatedUsage) - } - case reflect.TypeOf(time.Duration(0)): - if name != "" { - f.flagSet.DurationVar(addr.(*time.Duration), name, iface.(time.Duration), flag.Usage) - } - if deprecatedName != "" { - f.flagSet.DurationVar(addr.(*time.Duration), deprecatedName, iface.(time.Duration), deprecatedUsage) - } - - case reflect.TypeOf([]string{}): - if name != "" { - f.flagSet.Var(stringSliceVar{value}, name, flag.Usage) - } - if deprecatedName != "" { - f.flagSet.Var(stringSliceVar{value}, deprecatedName, deprecatedUsage) - } - default: - return GinkgoFlagSet{}, fmt.Errorf("unsupported type %T", iface) - } - } - - return f, nil -} - -func (f GinkgoFlagSet) IsZero() bool { - return f.flagSet == nil -} - -func (f GinkgoFlagSet) WasSet(name string) bool { - found := false - f.flagSet.Visit(func(f *flag.Flag) { - if f.Name == name { - found = true - } - }) - - return found -} - -func (f GinkgoFlagSet) Lookup(name string) *flag.Flag { - return f.flagSet.Lookup(name) -} - -func (f GinkgoFlagSet) Parse(args []string) ([]string, error) { - if f.IsZero() { - return args, nil - } - err := f.flagSet.Parse(args) - if err != nil { - return []string{}, err - } - return f.flagSet.Args(), nil -} - -func (f GinkgoFlagSet) ValidateDeprecations(deprecationTracker *DeprecationTracker) { - if f.IsZero() { - return - } - f.flagSet.Visit(func(flag *flag.Flag) { - for _, ginkgoFlag := range f.flags { - if ginkgoFlag.DeprecatedName != "" && strings.HasSuffix(flag.Name, ginkgoFlag.DeprecatedName) { - message := fmt.Sprintf("--%s is deprecated", ginkgoFlag.DeprecatedName) - if ginkgoFlag.Name != "" { - message = fmt.Sprintf("--%s is deprecated, use --%s instead", ginkgoFlag.DeprecatedName, ginkgoFlag.Name) - } else if ginkgoFlag.Usage != "" { - message += " " + ginkgoFlag.Usage - } - - deprecationTracker.TrackDeprecation(Deprecation{ - Message: message, - DocLink: ginkgoFlag.DeprecatedDocLink, - Version: ginkgoFlag.DeprecatedVersion, - }) - } - } - }) -} - -func (f GinkgoFlagSet) Usage() string { - if f.IsZero() { - return "" - } - groupedFlags := map[GinkgoFlagSection]GinkgoFlags{} - ungroupedFlags := GinkgoFlags{} - managedFlags := map[string]bool{} - extraGoFlags := []*flag.Flag{} - - for _, flag := range f.flags { - managedFlags[flag.Name] = true - managedFlags[flag.DeprecatedName] = true - - if flag.Name == "" { - continue - } - - section, ok := f.sections.Lookup(flag.SectionKey) - if ok { - groupedFlags[section] = append(groupedFlags[section], flag) - } else { - ungroupedFlags = append(ungroupedFlags, flag) - } - } - - f.flagSet.VisitAll(func(flag *flag.Flag) { - if !managedFlags[flag.Name] { - extraGoFlags = append(extraGoFlags, flag) - } - }) - - out := "" - for _, section := range f.sections { - flags := groupedFlags[section] - if len(flags) == 0 { - continue - } - out += f.usageForSection(section) - if section.Succinct { - succinctFlags := []string{} - for _, flag := range flags { - if flag.Name != "" { - succinctFlags = append(succinctFlags, fmt.Sprintf("--%s", flag.Name)) - } - } - out += formatter.Fiw(1, formatter.COLS, section.Style+strings.Join(succinctFlags, ", ")+"{{/}}\n") - } else { - for _, flag := range flags { - out += f.usageForFlag(flag, section.Style) - } - } - out += "\n" - } - if len(ungroupedFlags) > 0 { - for _, flag := range ungroupedFlags { - out += f.usageForFlag(flag, "") - } - out += "\n" - } - if len(extraGoFlags) > 0 { - out += f.usageForSection(f.extraGoFlagsSection) - for _, goFlag := range extraGoFlags { - out += f.usageForGoFlag(goFlag) - } - } - - return out -} - -func (f GinkgoFlagSet) substituteUsage() { - fmt.Fprintln(f.flagSet.Output(), f.Usage()) -} - -func valueAtKeyPath(root interface{}, keyPath string) (reflect.Value, bool) { - if len(keyPath) == 0 { - return reflect.Value{}, false - } - - val := reflect.ValueOf(root) - components := strings.Split(keyPath, ".") - for _, component := range components { - val = reflect.Indirect(val) - switch val.Kind() { - case reflect.Map: - val = val.MapIndex(reflect.ValueOf(component)) - if val.Kind() == reflect.Interface { - val = reflect.ValueOf(val.Interface()) - } - case reflect.Struct: - val = val.FieldByName(component) - default: - return reflect.Value{}, false - } - if (val == reflect.Value{}) { - return reflect.Value{}, false - } - } - - return val, true -} - -func (f GinkgoFlagSet) usageForSection(section GinkgoFlagSection) string { - out := formatter.F(section.Style + "{{bold}}{{underline}}" + section.Heading + "{{/}}\n") - if section.Description != "" { - out += formatter.Fiw(0, formatter.COLS, section.Description+"\n") - } - return out -} - -func (f GinkgoFlagSet) usageForFlag(flag GinkgoFlag, style string) string { - argument := flag.UsageArgument - defValue := flag.UsageDefaultValue - if argument == "" { - value, _ := valueAtKeyPath(f.bindings, flag.KeyPath) - switch value.Type() { - case reflect.TypeOf(string("")): - argument = "string" - case reflect.TypeOf(int64(0)), reflect.TypeOf(int(0)): - argument = "int" - case reflect.TypeOf(time.Duration(0)): - argument = "duration" - case reflect.TypeOf(float64(0)): - argument = "float" - case reflect.TypeOf([]string{}): - argument = "string" - } - } - if argument != "" { - argument = "[" + argument + "] " - } - if defValue != "" { - defValue = fmt.Sprintf("(default: %s)", defValue) - } - hyphens := "--" - if len(flag.Name) == 1 { - hyphens = "-" - } - - out := formatter.Fi(1, style+"%s%s{{/}} %s{{gray}}%s{{/}}\n", hyphens, flag.Name, argument, defValue) - out += formatter.Fiw(2, formatter.COLS, "{{light-gray}}%s{{/}}\n", flag.Usage) - return out -} - -func (f GinkgoFlagSet) usageForGoFlag(goFlag *flag.Flag) string { - //Taken directly from the flag package - out := fmt.Sprintf(" -%s", goFlag.Name) - name, usage := flag.UnquoteUsage(goFlag) - if len(name) > 0 { - out += " " + name - } - if len(out) <= 4 { - out += "\t" - } else { - out += "\n \t" - } - out += strings.ReplaceAll(usage, "\n", "\n \t") - out += "\n" - return out -} - -type stringSliceVar struct { - slice reflect.Value -} - -func (ssv stringSliceVar) String() string { return "" } -func (ssv stringSliceVar) Set(s string) error { - ssv.slice.Set(reflect.AppendSlice(ssv.slice, reflect.ValueOf([]string{s}))) - return nil -} - -//given a set of GinkgoFlags and bindings, generate flag arguments suitable to be passed to an application with that set of flags configured. -func GenerateFlagArgs(flags GinkgoFlags, bindings interface{}) ([]string, error) { - result := []string{} - for _, flag := range flags { - name := flag.ExportAs - if name == "" { - name = flag.Name - } - if name == "" { - continue - } - - value, ok := valueAtKeyPath(bindings, flag.KeyPath) - if !ok { - return []string{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath) - } - - iface := value.Interface() - switch value.Type() { - case reflect.TypeOf(string("")): - if iface.(string) != "" { - result = append(result, fmt.Sprintf("--%s=%s", name, iface)) - } - case reflect.TypeOf(int64(0)): - if iface.(int64) != 0 { - result = append(result, fmt.Sprintf("--%s=%d", name, iface)) - } - case reflect.TypeOf(float64(0)): - if iface.(float64) != 0 { - result = append(result, fmt.Sprintf("--%s=%f", name, iface)) - } - case reflect.TypeOf(int(0)): - if iface.(int) != 0 { - result = append(result, fmt.Sprintf("--%s=%d", name, iface)) - } - case reflect.TypeOf(bool(true)): - if iface.(bool) { - result = append(result, fmt.Sprintf("--%s", name)) - } - case reflect.TypeOf(time.Duration(0)): - if iface.(time.Duration) != time.Duration(0) { - result = append(result, fmt.Sprintf("--%s=%s", name, iface)) - } - - case reflect.TypeOf([]string{}): - strings := iface.([]string) - for _, s := range strings { - result = append(result, fmt.Sprintf("--%s=%s", name, s)) - } - default: - return []string{}, fmt.Errorf("unsupported type %T", iface) - } - } - - return result, nil -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go b/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go deleted file mode 100644 index b0d3b651e7..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go +++ /dev/null @@ -1,358 +0,0 @@ -package types - -import ( - "fmt" - "regexp" - "strings" -) - -var DEBUG_LABEL_FILTER_PARSING = false - -type LabelFilter func([]string) bool - -func matchLabelAction(label string) LabelFilter { - expected := strings.ToLower(label) - return func(labels []string) bool { - for i := range labels { - if strings.ToLower(labels[i]) == expected { - return true - } - } - return false - } -} - -func matchLabelRegexAction(regex *regexp.Regexp) LabelFilter { - return func(labels []string) bool { - for i := range labels { - if regex.MatchString(labels[i]) { - return true - } - } - return false - } -} - -func notAction(filter LabelFilter) LabelFilter { - return func(labels []string) bool { return !filter(labels) } -} - -func andAction(a, b LabelFilter) LabelFilter { - return func(labels []string) bool { return a(labels) && b(labels) } -} - -func orAction(a, b LabelFilter) LabelFilter { - return func(labels []string) bool { return a(labels) || b(labels) } -} - -type lfToken uint - -const ( - lfTokenInvalid lfToken = iota - - lfTokenRoot - lfTokenOpenGroup - lfTokenCloseGroup - lfTokenNot - lfTokenAnd - lfTokenOr - lfTokenRegexp - lfTokenLabel - lfTokenEOF -) - -func (l lfToken) Precedence() int { - switch l { - case lfTokenRoot, lfTokenOpenGroup: - return 0 - case lfTokenOr: - return 1 - case lfTokenAnd: - return 2 - case lfTokenNot: - return 3 - } - return -1 -} - -func (l lfToken) String() string { - switch l { - case lfTokenRoot: - return "ROOT" - case lfTokenOpenGroup: - return "(" - case lfTokenCloseGroup: - return ")" - case lfTokenNot: - return "!" - case lfTokenAnd: - return "&&" - case lfTokenOr: - return "||" - case lfTokenRegexp: - return "/regexp/" - case lfTokenLabel: - return "label" - case lfTokenEOF: - return "EOF" - } - return "INVALID" -} - -type treeNode struct { - token lfToken - location int - value string - - parent *treeNode - leftNode *treeNode - rightNode *treeNode -} - -func (tn *treeNode) setRightNode(node *treeNode) { - tn.rightNode = node - node.parent = tn -} - -func (tn *treeNode) setLeftNode(node *treeNode) { - tn.leftNode = node - node.parent = tn -} - -func (tn *treeNode) firstAncestorWithPrecedenceLEQ(precedence int) *treeNode { - if tn.token.Precedence() <= precedence { - return tn - } - return tn.parent.firstAncestorWithPrecedenceLEQ(precedence) -} - -func (tn *treeNode) firstUnmatchedOpenNode() *treeNode { - if tn.token == lfTokenOpenGroup { - return tn - } - if tn.parent == nil { - return nil - } - return tn.parent.firstUnmatchedOpenNode() -} - -func (tn *treeNode) constructLabelFilter(input string) (LabelFilter, error) { - switch tn.token { - case lfTokenOpenGroup: - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, "Mismatched '(' - could not find matching ')'.") - case lfTokenLabel: - return matchLabelAction(tn.value), nil - case lfTokenRegexp: - re, err := regexp.Compile(tn.value) - if err != nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("RegExp compilation error: %s", err)) - } - return matchLabelRegexAction(re), nil - } - - if tn.rightNode == nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, -1, "Unexpected EOF.") - } - rightLF, err := tn.rightNode.constructLabelFilter(input) - if err != nil { - return nil, err - } - - switch tn.token { - case lfTokenRoot, lfTokenCloseGroup: - return rightLF, nil - case lfTokenNot: - return notAction(rightLF), nil - } - - if tn.leftNode == nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Malformed tree - '%s' is missing left operand.", tn.token)) - } - leftLF, err := tn.leftNode.constructLabelFilter(input) - if err != nil { - return nil, err - } - - switch tn.token { - case lfTokenAnd: - return andAction(leftLF, rightLF), nil - case lfTokenOr: - return orAction(leftLF, rightLF), nil - } - - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Invalid token '%s'.", tn.token)) -} - -func (tn *treeNode) tokenString() string { - out := fmt.Sprintf("<%s", tn.token) - if tn.value != "" { - out += " | " + tn.value - } - out += ">" - return out -} - -func (tn *treeNode) toString(indent int) string { - out := tn.tokenString() + "\n" - if tn.leftNode != nil { - out += fmt.Sprintf("%s |_(L)_%s", strings.Repeat(" ", indent), tn.leftNode.toString(indent+1)) - } - if tn.rightNode != nil { - out += fmt.Sprintf("%s |_(R)_%s", strings.Repeat(" ", indent), tn.rightNode.toString(indent+1)) - } - return out -} - -func tokenize(input string) func() (*treeNode, error) { - runes, i := []rune(input), 0 - - peekIs := func(r rune) bool { - if i+1 < len(runes) { - return runes[i+1] == r - } - return false - } - - consumeUntil := func(cutset string) (string, int) { - j := i - for ; j < len(runes); j++ { - if strings.IndexRune(cutset, runes[j]) >= 0 { - break - } - } - return string(runes[i:j]), j - i - } - - return func() (*treeNode, error) { - for i < len(runes) && runes[i] == ' ' { - i += 1 - } - - if i >= len(runes) { - return &treeNode{token: lfTokenEOF}, nil - } - - node := &treeNode{location: i} - switch runes[i] { - case '&': - if !peekIs('&') { - return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Invalid token '&'. Did you mean '&&'?") - } - i += 2 - node.token = lfTokenAnd - case '|': - if !peekIs('|') { - return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Invalid token '|'. Did you mean '||'?") - } - i += 2 - node.token = lfTokenOr - case '!': - i += 1 - node.token = lfTokenNot - case ',': - i += 1 - node.token = lfTokenOr - case '(': - i += 1 - node.token = lfTokenOpenGroup - case ')': - i += 1 - node.token = lfTokenCloseGroup - case '/': - i += 1 - value, n := consumeUntil("/") - i += n + 1 - node.token, node.value = lfTokenRegexp, value - default: - value, n := consumeUntil("&|!,()/") - i += n - node.token, node.value = lfTokenLabel, strings.TrimSpace(value) - } - return node, nil - } -} - -func MustParseLabelFilter(input string) LabelFilter { - filter, err := ParseLabelFilter(input) - if err != nil { - panic(err) - } - return filter -} - -func ParseLabelFilter(input string) (LabelFilter, error) { - if DEBUG_LABEL_FILTER_PARSING { - fmt.Println("\n==============") - fmt.Println("Input: ", input) - fmt.Print("Tokens: ") - } - if input == "" { - return func(_ []string) bool { return true }, nil - } - nextToken := tokenize(input) - - root := &treeNode{token: lfTokenRoot} - current := root -LOOP: - for { - node, err := nextToken() - if err != nil { - return nil, err - } - - if DEBUG_LABEL_FILTER_PARSING { - fmt.Print(node.tokenString() + " ") - } - - switch node.token { - case lfTokenEOF: - break LOOP - case lfTokenLabel, lfTokenRegexp: - if current.rightNode != nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found two adjacent labels. You need an operator between them.") - } - current.setRightNode(node) - case lfTokenNot, lfTokenOpenGroup: - if current.rightNode != nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Invalid token '%s'.", node.token)) - } - current.setRightNode(node) - current = node - case lfTokenAnd, lfTokenOr: - if current.rightNode == nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Operator '%s' missing left hand operand.", node.token)) - } - nodeToStealFrom := current.firstAncestorWithPrecedenceLEQ(node.token.Precedence()) - node.setLeftNode(nodeToStealFrom.rightNode) - nodeToStealFrom.setRightNode(node) - current = node - case lfTokenCloseGroup: - firstUnmatchedOpenNode := current.firstUnmatchedOpenNode() - if firstUnmatchedOpenNode == nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Mismatched ')' - could not find matching '('.") - } - if firstUnmatchedOpenNode == current && current.rightNode == nil { - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found empty '()' group.") - } - firstUnmatchedOpenNode.token = lfTokenCloseGroup //signify the group is now closed - current = firstUnmatchedOpenNode.parent - default: - return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Unknown token '%s'.", node.token)) - } - } - if DEBUG_LABEL_FILTER_PARSING { - fmt.Printf("\n Tree:\n%s", root.toString(0)) - } - return root.constructLabelFilter(input) -} - -func ValidateAndCleanupLabel(label string, cl CodeLocation) (string, error) { - out := strings.TrimSpace(label) - if out == "" { - return "", GinkgoErrors.InvalidEmptyLabel(cl) - } - if strings.ContainsAny(out, "&|!,()/") { - return "", GinkgoErrors.InvalidLabel(label, cl) - } - return out, nil -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go b/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go deleted file mode 100644 index 7b1524b52e..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go +++ /dev/null @@ -1,190 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - "time" -) - -// ReportEntryValue wraps a report entry's value ensuring it can be encoded and decoded safely into reports -// and across the network connection when running in parallel -type ReportEntryValue struct { - raw interface{} //unexported to prevent gob from freaking out about unregistered structs - AsJSON string - Representation string -} - -func WrapEntryValue(value interface{}) ReportEntryValue { - return ReportEntryValue{ - raw: value, - } -} - -func (rev ReportEntryValue) GetRawValue() interface{} { - return rev.raw -} - -func (rev ReportEntryValue) String() string { - if rev.raw == nil { - return "" - } - if colorableStringer, ok := rev.raw.(ColorableStringer); ok { - return colorableStringer.ColorableString() - } - - if stringer, ok := rev.raw.(fmt.Stringer); ok { - return stringer.String() - } - if rev.Representation != "" { - return rev.Representation - } - return fmt.Sprintf("%+v", rev.raw) -} - -func (rev ReportEntryValue) MarshalJSON() ([]byte, error) { - //All this to capture the representation at encoding-time, not creating time - //This way users can Report on pointers and get their final values at reporting-time - out := struct { - AsJSON string - Representation string - }{ - Representation: rev.String(), - } - asJSON, err := json.Marshal(rev.raw) - if err != nil { - return nil, err - } - out.AsJSON = string(asJSON) - - return json.Marshal(out) -} - -func (rev *ReportEntryValue) UnmarshalJSON(data []byte) error { - in := struct { - AsJSON string - Representation string - }{} - err := json.Unmarshal(data, &in) - if err != nil { - return err - } - rev.AsJSON = in.AsJSON - rev.Representation = in.Representation - return json.Unmarshal([]byte(in.AsJSON), &(rev.raw)) -} - -func (rev ReportEntryValue) GobEncode() ([]byte, error) { - return rev.MarshalJSON() -} - -func (rev *ReportEntryValue) GobDecode(data []byte) error { - return rev.UnmarshalJSON(data) -} - -// ReportEntry captures information attached to `SpecReport` via `AddReportEntry` -type ReportEntry struct { - // Visibility captures the visibility policy for this ReportEntry - Visibility ReportEntryVisibility - // Location captures the location of the AddReportEntry call - Location CodeLocation - - Time time.Time //need this for backwards compatibility - TimelineLocation TimelineLocation - - // Name captures the name of this report - Name string - // Value captures the (optional) object passed into AddReportEntry - this can be - // anything the user wants. The value passed to AddReportEntry is wrapped in a ReportEntryValue to make - // encoding/decoding the value easier. To access the raw value call entry.GetRawValue() - Value ReportEntryValue -} - -// ColorableStringer is an interface that ReportEntry values can satisfy. If they do then ColorableString() is used to generate their representation. -type ColorableStringer interface { - ColorableString() string -} - -// StringRepresentation() returns the string representation of the value associated with the ReportEntry -- -// if value is nil, empty string is returned -// if value is a `ColorableStringer` then `Value.ColorableString()` is returned -// if value is a `fmt.Stringer` then `Value.String()` is returned -// otherwise the value is formatted with "%+v" -func (entry ReportEntry) StringRepresentation() string { - return entry.Value.String() -} - -// GetRawValue returns the Value object that was passed to AddReportEntry -// If called in-process this will be the same object that was passed into AddReportEntry. -// If used from a rehydrated JSON file _or_ in a ReportAfterSuite when running in parallel this will be -// a JSON-decoded {}interface. If you want to reconstitute your original object you can decode the entry.Value.AsJSON -// field yourself. -func (entry ReportEntry) GetRawValue() interface{} { - return entry.Value.GetRawValue() -} - -func (entry ReportEntry) GetTimelineLocation() TimelineLocation { - return entry.TimelineLocation -} - -type ReportEntries []ReportEntry - -func (re ReportEntries) HasVisibility(visibilities ...ReportEntryVisibility) bool { - for _, entry := range re { - if entry.Visibility.Is(visibilities...) { - return true - } - } - return false -} - -func (re ReportEntries) WithVisibility(visibilities ...ReportEntryVisibility) ReportEntries { - out := ReportEntries{} - - for _, entry := range re { - if entry.Visibility.Is(visibilities...) { - out = append(out, entry) - } - } - - return out -} - -// ReportEntryVisibility governs the visibility of ReportEntries in Ginkgo's console reporter -type ReportEntryVisibility uint - -const ( - // Always print out this ReportEntry - ReportEntryVisibilityAlways ReportEntryVisibility = iota - // Only print out this ReportEntry if the spec fails or if the test is run with -v - ReportEntryVisibilityFailureOrVerbose - // Never print out this ReportEntry (note that ReportEntrys are always encoded in machine readable reports (e.g. JSON, JUnit, etc.)) - ReportEntryVisibilityNever -) - -var revEnumSupport = NewEnumSupport(map[uint]string{ - uint(ReportEntryVisibilityAlways): "always", - uint(ReportEntryVisibilityFailureOrVerbose): "failure-or-verbose", - uint(ReportEntryVisibilityNever): "never", -}) - -func (rev ReportEntryVisibility) String() string { - return revEnumSupport.String(uint(rev)) -} -func (rev *ReportEntryVisibility) UnmarshalJSON(b []byte) error { - out, err := revEnumSupport.UnmarshJSON(b) - *rev = ReportEntryVisibility(out) - return err -} -func (rev ReportEntryVisibility) MarshalJSON() ([]byte, error) { - return revEnumSupport.MarshJSON(uint(rev)) -} - -func (v ReportEntryVisibility) Is(visibilities ...ReportEntryVisibility) bool { - for _, visibility := range visibilities { - if v == visibility { - return true - } - } - - return false -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/types.go b/vendor/github.com/onsi/ginkgo/v2/types/types.go deleted file mode 100644 index d048a8adab..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/types.go +++ /dev/null @@ -1,916 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - "sort" - "strings" - "time" -) - -const GINKGO_FOCUS_EXIT_CODE = 197 -const GINKGO_TIME_FORMAT = "01/02/06 15:04:05.999" - -// Report captures information about a Ginkgo test run -type Report struct { - //SuitePath captures the absolute path to the test suite - SuitePath string - - //SuiteDescription captures the description string passed to the DSL's RunSpecs() function - SuiteDescription string - - //SuiteLabels captures any labels attached to the suite by the DSL's RunSpecs() function - SuiteLabels []string - - //SuiteSucceeded captures the success or failure status of the test run - //If true, the test run is considered successful. - //If false, the test run is considered unsuccessful - SuiteSucceeded bool - - //SuiteHasProgrammaticFocus captures whether the test suite has a test or set of tests that are programmatically focused - //(i.e an `FIt` or an `FDescribe` - SuiteHasProgrammaticFocus bool - - //SpecialSuiteFailureReasons may contain special failure reasons - //For example, a test suite might be considered "failed" even if none of the individual specs - //have a failure state. For example, if the user has configured --fail-on-pending the test suite - //will have failed if there are pending tests even though all non-pending tests may have passed. In such - //cases, Ginkgo populates SpecialSuiteFailureReasons with a clear message indicating the reason for the failure. - //SpecialSuiteFailureReasons is also populated if the test suite is interrupted by the user. - //Since multiple special failure reasons can occur, this field is a slice. - SpecialSuiteFailureReasons []string - - //PreRunStats contains a set of stats captured before the test run begins. This is primarily used - //by Ginkgo's reporter to tell the user how many specs are in the current suite (PreRunStats.TotalSpecs) - //and how many it intends to run (PreRunStats.SpecsThatWillRun) after applying any relevant focus or skip filters. - PreRunStats PreRunStats - - //StartTime and EndTime capture the start and end time of the test run - StartTime time.Time - EndTime time.Time - - //RunTime captures the duration of the test run - RunTime time.Duration - - //SuiteConfig captures the Ginkgo configuration governing this test run - //SuiteConfig includes information necessary for reproducing an identical test run, - //such as the random seed and any filters applied during the test run - SuiteConfig SuiteConfig - - //SpecReports is a list of all SpecReports generated by this test run - //It is empty when the SuiteReport is provided to ReportBeforeSuite - SpecReports SpecReports -} - -// PreRunStats contains a set of stats captured before the test run begins. This is primarily used -// by Ginkgo's reporter to tell the user how many specs are in the current suite (PreRunStats.TotalSpecs) -// and how many it intends to run (PreRunStats.SpecsThatWillRun) after applying any relevant focus or skip filters. -type PreRunStats struct { - TotalSpecs int - SpecsThatWillRun int -} - -// Add is used by Ginkgo's parallel aggregation mechanisms to combine test run reports form individual parallel processes -// to form a complete final report. -func (report Report) Add(other Report) Report { - report.SuiteSucceeded = report.SuiteSucceeded && other.SuiteSucceeded - - if other.StartTime.Before(report.StartTime) { - report.StartTime = other.StartTime - } - - if other.EndTime.After(report.EndTime) { - report.EndTime = other.EndTime - } - - specialSuiteFailureReasons := []string{} - reasonsLookup := map[string]bool{} - for _, reasons := range [][]string{report.SpecialSuiteFailureReasons, other.SpecialSuiteFailureReasons} { - for _, reason := range reasons { - if !reasonsLookup[reason] { - reasonsLookup[reason] = true - specialSuiteFailureReasons = append(specialSuiteFailureReasons, reason) - } - } - } - report.SpecialSuiteFailureReasons = specialSuiteFailureReasons - report.RunTime = report.EndTime.Sub(report.StartTime) - - reports := make(SpecReports, len(report.SpecReports)+len(other.SpecReports)) - for i := range report.SpecReports { - reports[i] = report.SpecReports[i] - } - offset := len(report.SpecReports) - for i := range other.SpecReports { - reports[i+offset] = other.SpecReports[i] - } - - report.SpecReports = reports - return report -} - -// SpecReport captures information about a Ginkgo spec. -type SpecReport struct { - // ContainerHierarchyTexts is a slice containing the text strings of - // all Describe/Context/When containers in this spec's hierarchy. - ContainerHierarchyTexts []string - - // ContainerHierarchyLocations is a slice containing the CodeLocations of - // all Describe/Context/When containers in this spec's hierarchy. - ContainerHierarchyLocations []CodeLocation - - // ContainerHierarchyLabels is a slice containing the labels of - // all Describe/Context/When containers in this spec's hierarchy - ContainerHierarchyLabels [][]string - - // LeafNodeType, LeadNodeLocation, LeafNodeLabels and LeafNodeText capture the NodeType, CodeLocation, and text - // of the Ginkgo node being tested (typically an NodeTypeIt node, though this can also be - // one of the NodeTypesForSuiteLevelNodes node types) - LeafNodeType NodeType - LeafNodeLocation CodeLocation - LeafNodeLabels []string - LeafNodeText string - - // State captures whether the spec has passed, failed, etc. - State SpecState - - // IsSerial captures whether the spec has the Serial decorator - IsSerial bool - - // IsInOrderedContainer captures whether the spec appears in an Ordered container - IsInOrderedContainer bool - - // StartTime and EndTime capture the start and end time of the spec - StartTime time.Time - EndTime time.Time - - // RunTime captures the duration of the spec - RunTime time.Duration - - // ParallelProcess captures the parallel process that this spec ran on - ParallelProcess int - - // RunningInParallel captures whether this spec is part of a suite that ran in parallel - RunningInParallel bool - - //Failure is populated if a spec has failed, panicked, been interrupted, or skipped by the user (e.g. calling Skip()) - //It includes detailed information about the Failure - Failure Failure - - // NumAttempts captures the number of times this Spec was run. - // Flakey specs can be retried with ginkgo --flake-attempts=N or the use of the FlakeAttempts decorator. - // Repeated specs can be retried with the use of the MustPassRepeatedly decorator - NumAttempts int - - // MaxFlakeAttempts captures whether the spec has been retried with ginkgo --flake-attempts=N or the use of the FlakeAttempts decorator. - MaxFlakeAttempts int - - // MaxMustPassRepeatedly captures whether the spec has the MustPassRepeatedly decorator - MaxMustPassRepeatedly int - - // CapturedGinkgoWriterOutput contains text printed to the GinkgoWriter - CapturedGinkgoWriterOutput string - - // CapturedStdOutErr contains text printed to stdout/stderr (when running in parallel) - // This is always empty when running in series or calling CurrentSpecReport() - // It is used internally by Ginkgo's reporter - CapturedStdOutErr string - - // ReportEntries contains any reports added via `AddReportEntry` - ReportEntries ReportEntries - - // ProgressReports contains any progress reports generated during this spec. These can either be manually triggered, or automatically generated by Ginkgo via the PollProgressAfter() decorator - ProgressReports []ProgressReport - - // AdditionalFailures contains any failures that occurred after the initial spec failure. These typically occur in cleanup nodes after the initial failure and are only emitted when running in verbose mode. - AdditionalFailures []AdditionalFailure - - // SpecEvents capture additional events that occur during the spec run - SpecEvents SpecEvents -} - -func (report SpecReport) MarshalJSON() ([]byte, error) { - //All this to avoid emitting an empty Failure struct in the JSON - out := struct { - ContainerHierarchyTexts []string - ContainerHierarchyLocations []CodeLocation - ContainerHierarchyLabels [][]string - LeafNodeType NodeType - LeafNodeLocation CodeLocation - LeafNodeLabels []string - LeafNodeText string - State SpecState - StartTime time.Time - EndTime time.Time - RunTime time.Duration - ParallelProcess int - Failure *Failure `json:",omitempty"` - NumAttempts int - MaxFlakeAttempts int - MaxMustPassRepeatedly int - CapturedGinkgoWriterOutput string `json:",omitempty"` - CapturedStdOutErr string `json:",omitempty"` - ReportEntries ReportEntries `json:",omitempty"` - ProgressReports []ProgressReport `json:",omitempty"` - AdditionalFailures []AdditionalFailure `json:",omitempty"` - SpecEvents SpecEvents `json:",omitempty"` - }{ - ContainerHierarchyTexts: report.ContainerHierarchyTexts, - ContainerHierarchyLocations: report.ContainerHierarchyLocations, - ContainerHierarchyLabels: report.ContainerHierarchyLabels, - LeafNodeType: report.LeafNodeType, - LeafNodeLocation: report.LeafNodeLocation, - LeafNodeLabels: report.LeafNodeLabels, - LeafNodeText: report.LeafNodeText, - State: report.State, - StartTime: report.StartTime, - EndTime: report.EndTime, - RunTime: report.RunTime, - ParallelProcess: report.ParallelProcess, - Failure: nil, - ReportEntries: nil, - NumAttempts: report.NumAttempts, - MaxFlakeAttempts: report.MaxFlakeAttempts, - MaxMustPassRepeatedly: report.MaxMustPassRepeatedly, - CapturedGinkgoWriterOutput: report.CapturedGinkgoWriterOutput, - CapturedStdOutErr: report.CapturedStdOutErr, - } - - if !report.Failure.IsZero() { - out.Failure = &(report.Failure) - } - if len(report.ReportEntries) > 0 { - out.ReportEntries = report.ReportEntries - } - if len(report.ProgressReports) > 0 { - out.ProgressReports = report.ProgressReports - } - if len(report.AdditionalFailures) > 0 { - out.AdditionalFailures = report.AdditionalFailures - } - if len(report.SpecEvents) > 0 { - out.SpecEvents = report.SpecEvents - } - - return json.Marshal(out) -} - -// CombinedOutput returns a single string representation of both CapturedStdOutErr and CapturedGinkgoWriterOutput -// Note that both are empty when using CurrentSpecReport() so CurrentSpecReport().CombinedOutput() will always be empty. -// CombinedOutput() is used internally by Ginkgo's reporter. -func (report SpecReport) CombinedOutput() string { - if report.CapturedStdOutErr == "" { - return report.CapturedGinkgoWriterOutput - } - if report.CapturedGinkgoWriterOutput == "" { - return report.CapturedStdOutErr - } - return report.CapturedStdOutErr + "\n" + report.CapturedGinkgoWriterOutput -} - -// Failed returns true if report.State is one of the SpecStateFailureStates -// (SpecStateFailed, SpecStatePanicked, SpecStateinterrupted, SpecStateAborted) -func (report SpecReport) Failed() bool { - return report.State.Is(SpecStateFailureStates) -} - -// FullText returns a concatenation of all the report.ContainerHierarchyTexts and report.LeafNodeText -func (report SpecReport) FullText() string { - texts := []string{} - texts = append(texts, report.ContainerHierarchyTexts...) - if report.LeafNodeText != "" { - texts = append(texts, report.LeafNodeText) - } - return strings.Join(texts, " ") -} - -// Labels returns a deduped set of all the spec's Labels. -func (report SpecReport) Labels() []string { - out := []string{} - seen := map[string]bool{} - for _, labels := range report.ContainerHierarchyLabels { - for _, label := range labels { - if !seen[label] { - seen[label] = true - out = append(out, label) - } - } - } - for _, label := range report.LeafNodeLabels { - if !seen[label] { - seen[label] = true - out = append(out, label) - } - } - - return out -} - -// MatchesLabelFilter returns true if the spec satisfies the passed in label filter query -func (report SpecReport) MatchesLabelFilter(query string) (bool, error) { - filter, err := ParseLabelFilter(query) - if err != nil { - return false, err - } - return filter(report.Labels()), nil -} - -// FileName() returns the name of the file containing the spec -func (report SpecReport) FileName() string { - return report.LeafNodeLocation.FileName -} - -// LineNumber() returns the line number of the leaf node -func (report SpecReport) LineNumber() int { - return report.LeafNodeLocation.LineNumber -} - -// FailureMessage() returns the failure message (or empty string if the test hasn't failed) -func (report SpecReport) FailureMessage() string { - return report.Failure.Message -} - -// FailureLocation() returns the location of the failure (or an empty CodeLocation if the test hasn't failed) -func (report SpecReport) FailureLocation() CodeLocation { - return report.Failure.Location -} - -// Timeline() returns a timeline view of the report -func (report SpecReport) Timeline() Timeline { - timeline := Timeline{} - if !report.Failure.IsZero() { - timeline = append(timeline, report.Failure) - if report.Failure.AdditionalFailure != nil { - timeline = append(timeline, *(report.Failure.AdditionalFailure)) - } - } - for _, additionalFailure := range report.AdditionalFailures { - timeline = append(timeline, additionalFailure) - } - for _, reportEntry := range report.ReportEntries { - timeline = append(timeline, reportEntry) - } - for _, progressReport := range report.ProgressReports { - timeline = append(timeline, progressReport) - } - for _, specEvent := range report.SpecEvents { - timeline = append(timeline, specEvent) - } - sort.Sort(timeline) - return timeline -} - -type SpecReports []SpecReport - -// WithLeafNodeType returns the subset of SpecReports with LeafNodeType matching one of the requested NodeTypes -func (reports SpecReports) WithLeafNodeType(nodeTypes NodeType) SpecReports { - count := 0 - for i := range reports { - if reports[i].LeafNodeType.Is(nodeTypes) { - count++ - } - } - - out := make(SpecReports, count) - j := 0 - for i := range reports { - if reports[i].LeafNodeType.Is(nodeTypes) { - out[j] = reports[i] - j++ - } - } - return out -} - -// WithState returns the subset of SpecReports with State matching one of the requested SpecStates -func (reports SpecReports) WithState(states SpecState) SpecReports { - count := 0 - for i := range reports { - if reports[i].State.Is(states) { - count++ - } - } - - out, j := make(SpecReports, count), 0 - for i := range reports { - if reports[i].State.Is(states) { - out[j] = reports[i] - j++ - } - } - return out -} - -// CountWithState returns the number of SpecReports with State matching one of the requested SpecStates -func (reports SpecReports) CountWithState(states SpecState) int { - n := 0 - for i := range reports { - if reports[i].State.Is(states) { - n += 1 - } - } - return n -} - -// If the Spec passes, CountOfFlakedSpecs returns the number of SpecReports that failed after multiple attempts. -func (reports SpecReports) CountOfFlakedSpecs() int { - n := 0 - for i := range reports { - if reports[i].MaxFlakeAttempts > 1 && reports[i].State.Is(SpecStatePassed) && reports[i].NumAttempts > 1 { - n += 1 - } - } - return n -} - -// If the Spec fails, CountOfRepeatedSpecs returns the number of SpecReports that passed after multiple attempts -func (reports SpecReports) CountOfRepeatedSpecs() int { - n := 0 - for i := range reports { - if reports[i].MaxMustPassRepeatedly > 1 && reports[i].State.Is(SpecStateFailureStates) && reports[i].NumAttempts > 1 { - n += 1 - } - } - return n -} - -// TimelineLocation captures the location of an event in the spec's timeline -type TimelineLocation struct { - //Offset is the offset (in bytes) of the event relative to the GinkgoWriter stream - Offset int `json:",omitempty"` - - //Order is the order of the event with respect to other events. The absolute value of Order - //is irrelevant. All that matters is that an event with a lower Order occurs before ane vent with a higher Order - Order int `json:",omitempty"` - - Time time.Time -} - -// TimelineEvent represent an event on the timeline -// consumers of Timeline will need to check the concrete type of each entry to determine how to handle it -type TimelineEvent interface { - GetTimelineLocation() TimelineLocation -} - -type Timeline []TimelineEvent - -func (t Timeline) Len() int { return len(t) } -func (t Timeline) Less(i, j int) bool { - return t[i].GetTimelineLocation().Order < t[j].GetTimelineLocation().Order -} -func (t Timeline) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t Timeline) WithoutHiddenReportEntries() Timeline { - out := Timeline{} - for _, event := range t { - if reportEntry, isReportEntry := event.(ReportEntry); isReportEntry && reportEntry.Visibility == ReportEntryVisibilityNever { - continue - } - out = append(out, event) - } - return out -} - -func (t Timeline) WithoutVeryVerboseSpecEvents() Timeline { - out := Timeline{} - for _, event := range t { - if specEvent, isSpecEvent := event.(SpecEvent); isSpecEvent && specEvent.IsOnlyVisibleAtVeryVerbose() { - continue - } - out = append(out, event) - } - return out -} - -// Failure captures failure information for an individual test -type Failure struct { - // Message - the failure message passed into Fail(...). When using a matcher library - // like Gomega, this will contain the failure message generated by Gomega. - // - // Message is also populated if the user has called Skip(...). - Message string - - // Location - the CodeLocation where the failure occurred - // This CodeLocation will include a fully-populated StackTrace - Location CodeLocation - - TimelineLocation TimelineLocation - - // ForwardedPanic - if the failure represents a captured panic (i.e. Summary.State == SpecStatePanicked) - // then ForwardedPanic will be populated with a string representation of the captured panic. - ForwardedPanic string `json:",omitempty"` - - // FailureNodeContext - one of three contexts describing the node in which the failure occurred: - // FailureNodeIsLeafNode means the failure occurred in the leaf node of the associated SpecReport. None of the other FailureNode fields will be populated - // FailureNodeAtTopLevel means the failure occurred in a non-leaf node that is defined at the top-level of the spec (i.e. not in a container). FailureNodeType and FailureNodeLocation will be populated. - // FailureNodeInContainer means the failure occurred in a non-leaf node that is defined within a container. FailureNodeType, FailureNodeLocation, and FailureNodeContainerIndex will be populated. - // - // FailureNodeType will contain the NodeType of the node in which the failure occurred. - // FailureNodeLocation will contain the CodeLocation of the node in which the failure occurred. - // If populated, FailureNodeContainerIndex will be the index into SpecReport.ContainerHierarchyTexts and SpecReport.ContainerHierarchyLocations that represents the parent container of the node in which the failure occurred. - FailureNodeContext FailureNodeContext `json:",omitempty"` - - FailureNodeType NodeType `json:",omitempty"` - - FailureNodeLocation CodeLocation `json:",omitempty"` - - FailureNodeContainerIndex int `json:",omitempty"` - - //ProgressReport is populated if the spec was interrupted or timed out - ProgressReport ProgressReport `json:",omitempty"` - - //AdditionalFailure is non-nil if a follow-on failure occurred within the same node after the primary failure. This only happens when a node has timed out or been interrupted. In such cases the AdditionalFailure can include information about where/why the spec was stuck. - AdditionalFailure *AdditionalFailure `json:",omitempty"` -} - -func (f Failure) IsZero() bool { - return f.Message == "" && (f.Location == CodeLocation{}) -} - -func (f Failure) GetTimelineLocation() TimelineLocation { - return f.TimelineLocation -} - -// FailureNodeContext captures the location context for the node containing the failing line of code -type FailureNodeContext uint - -const ( - FailureNodeContextInvalid FailureNodeContext = iota - - FailureNodeIsLeafNode - FailureNodeAtTopLevel - FailureNodeInContainer -) - -var fncEnumSupport = NewEnumSupport(map[uint]string{ - uint(FailureNodeContextInvalid): "INVALID FAILURE NODE CONTEXT", - uint(FailureNodeIsLeafNode): "leaf-node", - uint(FailureNodeAtTopLevel): "top-level", - uint(FailureNodeInContainer): "in-container", -}) - -func (fnc FailureNodeContext) String() string { - return fncEnumSupport.String(uint(fnc)) -} -func (fnc *FailureNodeContext) UnmarshalJSON(b []byte) error { - out, err := fncEnumSupport.UnmarshJSON(b) - *fnc = FailureNodeContext(out) - return err -} -func (fnc FailureNodeContext) MarshalJSON() ([]byte, error) { - return fncEnumSupport.MarshJSON(uint(fnc)) -} - -// AdditionalFailure capturs any additional failures that occur after the initial failure of a psec -// these typically occur in clean up nodes after the spec has failed. -// We can't simply use Failure as we want to track the SpecState to know what kind of failure this is -type AdditionalFailure struct { - State SpecState - Failure Failure -} - -func (f AdditionalFailure) GetTimelineLocation() TimelineLocation { - return f.Failure.TimelineLocation -} - -// SpecState captures the state of a spec -// To determine if a given `state` represents a failure state, use `state.Is(SpecStateFailureStates)` -type SpecState uint - -const ( - SpecStateInvalid SpecState = 0 - - SpecStatePending SpecState = 1 << iota - SpecStateSkipped - SpecStatePassed - SpecStateFailed - SpecStateAborted - SpecStatePanicked - SpecStateInterrupted - SpecStateTimedout -) - -var ssEnumSupport = NewEnumSupport(map[uint]string{ - uint(SpecStateInvalid): "INVALID SPEC STATE", - uint(SpecStatePending): "pending", - uint(SpecStateSkipped): "skipped", - uint(SpecStatePassed): "passed", - uint(SpecStateFailed): "failed", - uint(SpecStateAborted): "aborted", - uint(SpecStatePanicked): "panicked", - uint(SpecStateInterrupted): "interrupted", - uint(SpecStateTimedout): "timedout", -}) - -func (ss SpecState) String() string { - return ssEnumSupport.String(uint(ss)) -} -func (ss SpecState) GomegaString() string { - return ssEnumSupport.String(uint(ss)) -} -func (ss *SpecState) UnmarshalJSON(b []byte) error { - out, err := ssEnumSupport.UnmarshJSON(b) - *ss = SpecState(out) - return err -} -func (ss SpecState) MarshalJSON() ([]byte, error) { - return ssEnumSupport.MarshJSON(uint(ss)) -} - -var SpecStateFailureStates = SpecStateFailed | SpecStateTimedout | SpecStateAborted | SpecStatePanicked | SpecStateInterrupted - -func (ss SpecState) Is(states SpecState) bool { - return ss&states != 0 -} - -// ProgressReport captures the progress of the current spec. It is, effectively, a structured Ginkgo-aware stack trace -type ProgressReport struct { - Message string `json:",omitempty"` - ParallelProcess int `json:",omitempty"` - RunningInParallel bool `json:",omitempty"` - - ContainerHierarchyTexts []string `json:",omitempty"` - LeafNodeText string `json:",omitempty"` - LeafNodeLocation CodeLocation `json:",omitempty"` - SpecStartTime time.Time `json:",omitempty"` - - CurrentNodeType NodeType `json:",omitempty"` - CurrentNodeText string `json:",omitempty"` - CurrentNodeLocation CodeLocation `json:",omitempty"` - CurrentNodeStartTime time.Time `json:",omitempty"` - - CurrentStepText string `json:",omitempty"` - CurrentStepLocation CodeLocation `json:",omitempty"` - CurrentStepStartTime time.Time `json:",omitempty"` - - AdditionalReports []string `json:",omitempty"` - - CapturedGinkgoWriterOutput string `json:",omitempty"` - TimelineLocation TimelineLocation `json:",omitempty"` - - Goroutines []Goroutine `json:",omitempty"` -} - -func (pr ProgressReport) IsZero() bool { - return pr.CurrentNodeType == NodeTypeInvalid -} - -func (pr ProgressReport) Time() time.Time { - return pr.TimelineLocation.Time -} - -func (pr ProgressReport) SpecGoroutine() Goroutine { - for _, goroutine := range pr.Goroutines { - if goroutine.IsSpecGoroutine { - return goroutine - } - } - return Goroutine{} -} - -func (pr ProgressReport) HighlightedGoroutines() []Goroutine { - out := []Goroutine{} - for _, goroutine := range pr.Goroutines { - if goroutine.IsSpecGoroutine || !goroutine.HasHighlights() { - continue - } - out = append(out, goroutine) - } - return out -} - -func (pr ProgressReport) OtherGoroutines() []Goroutine { - out := []Goroutine{} - for _, goroutine := range pr.Goroutines { - if goroutine.IsSpecGoroutine || goroutine.HasHighlights() { - continue - } - out = append(out, goroutine) - } - return out -} - -func (pr ProgressReport) WithoutCapturedGinkgoWriterOutput() ProgressReport { - out := pr - out.CapturedGinkgoWriterOutput = "" - return out -} - -func (pr ProgressReport) WithoutOtherGoroutines() ProgressReport { - out := pr - filteredGoroutines := []Goroutine{} - for _, goroutine := range pr.Goroutines { - if goroutine.IsSpecGoroutine || goroutine.HasHighlights() { - filteredGoroutines = append(filteredGoroutines, goroutine) - } - } - out.Goroutines = filteredGoroutines - return out -} - -func (pr ProgressReport) GetTimelineLocation() TimelineLocation { - return pr.TimelineLocation -} - -type Goroutine struct { - ID uint64 - State string - Stack []FunctionCall - IsSpecGoroutine bool -} - -func (g Goroutine) IsZero() bool { - return g.ID == 0 -} - -func (g Goroutine) HasHighlights() bool { - for _, fc := range g.Stack { - if fc.Highlight { - return true - } - } - - return false -} - -type FunctionCall struct { - Function string - Filename string - Line int - Highlight bool `json:",omitempty"` - Source []string `json:",omitempty"` - SourceHighlight int `json:",omitempty"` -} - -// NodeType captures the type of a given Ginkgo Node -type NodeType uint - -const ( - NodeTypeInvalid NodeType = 0 - - NodeTypeContainer NodeType = 1 << iota - NodeTypeIt - - NodeTypeBeforeEach - NodeTypeJustBeforeEach - NodeTypeAfterEach - NodeTypeJustAfterEach - - NodeTypeBeforeAll - NodeTypeAfterAll - - NodeTypeBeforeSuite - NodeTypeSynchronizedBeforeSuite - NodeTypeAfterSuite - NodeTypeSynchronizedAfterSuite - - NodeTypeReportBeforeEach - NodeTypeReportAfterEach - NodeTypeReportBeforeSuite - NodeTypeReportAfterSuite - - NodeTypeCleanupInvalid - NodeTypeCleanupAfterEach - NodeTypeCleanupAfterAll - NodeTypeCleanupAfterSuite -) - -var NodeTypesForContainerAndIt = NodeTypeContainer | NodeTypeIt -var NodeTypesForSuiteLevelNodes = NodeTypeBeforeSuite | NodeTypeSynchronizedBeforeSuite | NodeTypeAfterSuite | NodeTypeSynchronizedAfterSuite | NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite | NodeTypeCleanupAfterSuite -var NodeTypesAllowedDuringCleanupInterrupt = NodeTypeAfterEach | NodeTypeJustAfterEach | NodeTypeAfterAll | NodeTypeAfterSuite | NodeTypeSynchronizedAfterSuite | NodeTypeCleanupAfterEach | NodeTypeCleanupAfterAll | NodeTypeCleanupAfterSuite -var NodeTypesAllowedDuringReportInterrupt = NodeTypeReportBeforeEach | NodeTypeReportAfterEach | NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite - -var ntEnumSupport = NewEnumSupport(map[uint]string{ - uint(NodeTypeInvalid): "INVALID NODE TYPE", - uint(NodeTypeContainer): "Container", - uint(NodeTypeIt): "It", - uint(NodeTypeBeforeEach): "BeforeEach", - uint(NodeTypeJustBeforeEach): "JustBeforeEach", - uint(NodeTypeAfterEach): "AfterEach", - uint(NodeTypeJustAfterEach): "JustAfterEach", - uint(NodeTypeBeforeAll): "BeforeAll", - uint(NodeTypeAfterAll): "AfterAll", - uint(NodeTypeBeforeSuite): "BeforeSuite", - uint(NodeTypeSynchronizedBeforeSuite): "SynchronizedBeforeSuite", - uint(NodeTypeAfterSuite): "AfterSuite", - uint(NodeTypeSynchronizedAfterSuite): "SynchronizedAfterSuite", - uint(NodeTypeReportBeforeEach): "ReportBeforeEach", - uint(NodeTypeReportAfterEach): "ReportAfterEach", - uint(NodeTypeReportBeforeSuite): "ReportBeforeSuite", - uint(NodeTypeReportAfterSuite): "ReportAfterSuite", - uint(NodeTypeCleanupInvalid): "DeferCleanup", - uint(NodeTypeCleanupAfterEach): "DeferCleanup (Each)", - uint(NodeTypeCleanupAfterAll): "DeferCleanup (All)", - uint(NodeTypeCleanupAfterSuite): "DeferCleanup (Suite)", -}) - -func (nt NodeType) String() string { - return ntEnumSupport.String(uint(nt)) -} -func (nt *NodeType) UnmarshalJSON(b []byte) error { - out, err := ntEnumSupport.UnmarshJSON(b) - *nt = NodeType(out) - return err -} -func (nt NodeType) MarshalJSON() ([]byte, error) { - return ntEnumSupport.MarshJSON(uint(nt)) -} - -func (nt NodeType) Is(nodeTypes NodeType) bool { - return nt&nodeTypes != 0 -} - -/* -SpecEvent captures a vareity of events that can occur when specs run. See SpecEventType for the list of available events. -*/ -type SpecEvent struct { - SpecEventType SpecEventType - - CodeLocation CodeLocation - TimelineLocation TimelineLocation - - Message string `json:",omitempty"` - Duration time.Duration `json:",omitempty"` - NodeType NodeType `json:",omitempty"` - Attempt int `json:",omitempty"` -} - -func (se SpecEvent) GetTimelineLocation() TimelineLocation { - return se.TimelineLocation -} - -func (se SpecEvent) IsOnlyVisibleAtVeryVerbose() bool { - return se.SpecEventType.Is(SpecEventByEnd | SpecEventNodeStart | SpecEventNodeEnd) -} - -func (se SpecEvent) GomegaString() string { - out := &strings.Builder{} - out.WriteString("[" + se.SpecEventType.String() + " SpecEvent] ") - if se.Message != "" { - out.WriteString("Message=") - out.WriteString(`"` + se.Message + `",`) - } - if se.Duration != 0 { - out.WriteString("Duration=" + se.Duration.String() + ",") - } - if se.NodeType != NodeTypeInvalid { - out.WriteString("NodeType=" + se.NodeType.String() + ",") - } - if se.Attempt != 0 { - out.WriteString(fmt.Sprintf("Attempt=%d", se.Attempt) + ",") - } - out.WriteString("CL=" + se.CodeLocation.String() + ",") - out.WriteString(fmt.Sprintf("TL.Offset=%d", se.TimelineLocation.Offset)) - - return out.String() -} - -type SpecEvents []SpecEvent - -func (se SpecEvents) WithType(seType SpecEventType) SpecEvents { - out := SpecEvents{} - for _, event := range se { - if event.SpecEventType.Is(seType) { - out = append(out, event) - } - } - return out -} - -type SpecEventType uint - -const ( - SpecEventInvalid SpecEventType = 0 - - SpecEventByStart SpecEventType = 1 << iota - SpecEventByEnd - SpecEventNodeStart - SpecEventNodeEnd - SpecEventSpecRepeat - SpecEventSpecRetry -) - -var seEnumSupport = NewEnumSupport(map[uint]string{ - uint(SpecEventInvalid): "INVALID SPEC EVENT", - uint(SpecEventByStart): "By", - uint(SpecEventByEnd): "By (End)", - uint(SpecEventNodeStart): "Node", - uint(SpecEventNodeEnd): "Node (End)", - uint(SpecEventSpecRepeat): "Repeat", - uint(SpecEventSpecRetry): "Retry", -}) - -func (se SpecEventType) String() string { - return seEnumSupport.String(uint(se)) -} -func (se *SpecEventType) UnmarshalJSON(b []byte) error { - out, err := seEnumSupport.UnmarshJSON(b) - *se = SpecEventType(out) - return err -} -func (se SpecEventType) MarshalJSON() ([]byte, error) { - return seEnumSupport.MarshJSON(uint(se)) -} - -func (se SpecEventType) Is(specEventTypes SpecEventType) bool { - return se&specEventTypes != 0 -} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go deleted file mode 100644 index 43066341e1..0000000000 --- a/vendor/github.com/onsi/ginkgo/v2/types/version.go +++ /dev/null @@ -1,3 +0,0 @@ -package types - -const VERSION = "2.9.5" diff --git a/vendor/github.com/quic-go/quic-go/.golangci.yml b/vendor/github.com/quic-go/quic-go/.golangci.yml index 656fa76dd6..0c9ecffa59 100644 --- a/vendor/github.com/quic-go/quic-go/.golangci.yml +++ b/vendor/github.com/quic-go/quic-go/.golangci.yml @@ -9,11 +9,13 @@ linters: - govet - ineffassign - misspell + - nolintlint - prealloc - staticcheck - unconvert - unparam - unused + - usetesting settings: depguard: rules: @@ -35,9 +37,22 @@ linters: deny: - pkg: crypto/rsa desc: "use crypto/ed25519 instead" + ginkgo: + list-mode: original + deny: + - pkg: github.com/onsi/ginkgo + desc: "use standard Go tests" + - pkg: github.com/onsi/ginkgo/v2 + desc: "use standard Go tests" + - pkg: github.com/onsi/gomega + desc: "use standard Go tests" misspell: ignore-rules: - ect + # see https://github.com/ldez/usetesting/issues/10 + usetesting: + context-background: false + context-todo: false exclusions: generated: lax presets: diff --git a/vendor/github.com/quic-go/quic-go/client.go b/vendor/github.com/quic-go/quic-go/client.go index 26cd835845..5386e59803 100644 --- a/vendor/github.com/quic-go/quic-go/client.go +++ b/vendor/github.com/quic-go/quic-go/client.go @@ -16,7 +16,7 @@ var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial // It resolves the address, and then creates a new UDP connection to dial the QUIC server. // When the QUIC connection is closed, this UDP connection is closed. // See [Dial] for more details. -func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (Connection, error) { +func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (*Conn, error) { udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { return nil, err @@ -29,12 +29,16 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi if err != nil { return nil, err } - return tr.dial(ctx, udpAddr, addr, tlsConf, conf, false) + conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, false) + if err != nil { + return nil, err + } + return conn, nil } // DialAddrEarly establishes a new 0-RTT QUIC connection to a server. // See [DialAddr] for more details. -func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { +func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (*Conn, error) { udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { return nil, err @@ -57,7 +61,7 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf * // DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn. // See [Dial] for more details. -func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { +func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) { dl, err := setupTransport(c, tlsConf, false) if err != nil { return nil, err @@ -74,12 +78,12 @@ func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tl // If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does), // ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP // will be used instead of ReadFrom and WriteTo to read/write packets. -// The tls.Config must define an application protocol (using NextProtos). +// The [tls.Config] must define an application protocol (using tls.Config.NextProtos). // // This is a convenience function. More advanced use cases should instantiate a [Transport], // which offers configuration options for a more fine-grained control of the connection establishment, // including reusing the underlying UDP socket for multiple QUIC connections. -func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) { +func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) { dl, err := setupTransport(c, tlsConf, false) if err != nil { return nil, err diff --git a/vendor/github.com/quic-go/quic-go/codecov.yml b/vendor/github.com/quic-go/quic-go/codecov.yml index 77e47fbe54..86ee596e2f 100644 --- a/vendor/github.com/quic-go/quic-go/codecov.yml +++ b/vendor/github.com/quic-go/quic-go/codecov.yml @@ -2,8 +2,10 @@ coverage: round: nearest ignore: - http3/gzip_reader.go + - example/ - interop/ - internal/handshake/cipher_suite.go + - internal/mocks/ - internal/utils/linkedlist/linkedlist.go - internal/testdata - logging/connection_tracer_multiplexer.go diff --git a/vendor/github.com/quic-go/quic-go/connection.go b/vendor/github.com/quic-go/quic-go/connection.go index 09e935d4f1..056cdb7405 100644 --- a/vendor/github.com/quic-go/quic-go/connection.go +++ b/vendor/github.com/quic-go/quic-go/connection.go @@ -30,23 +30,6 @@ type unpacker interface { UnpackShortHeader(rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) } -type streamManager interface { - GetOrOpenSendStream(protocol.StreamID) (sendStreamI, error) - GetOrOpenReceiveStream(protocol.StreamID) (receiveStreamI, error) - OpenStream() (Stream, error) - OpenUniStream() (SendStream, error) - OpenStreamSync(context.Context) (Stream, error) - OpenUniStreamSync(context.Context) (SendStream, error) - AcceptStream(context.Context) (Stream, error) - AcceptUniStream(context.Context) (ReceiveStream, error) - DeleteStream(protocol.StreamID) error - UpdateLimits(*wire.TransportParameters) - HandleMaxStreamsFrame(*wire.MaxStreamsFrame) - CloseWithError(error) - ResetFor0RTT() - UseResetMaps() -} - type cryptoStreamHandler interface { StartHandshake(context.Context) error ChangeConnectionID(protocol.ConnectionID) @@ -110,8 +93,15 @@ func (e *errCloseForRecreating) Error() string { var connTracingID atomic.Uint64 // to be accessed atomically func nextConnTracingID() ConnectionTracingID { return ConnectionTracingID(connTracingID.Add(1)) } -// A Connection is a QUIC connection -type connection struct { +// A Conn is a QUIC connection between two peers. +// Calls to the connection (and to streams) can return the following types of errors: +// - [ApplicationError]: for errors triggered by the application running on top of QUIC +// - [TransportError]: for errors triggered by the QUIC transport (in many cases a misbehaving peer) +// - [IdleTimeoutError]: when the peer goes away unexpectedly (this is a [net.Error] timeout error) +// - [HandshakeTimeoutError]: when the cryptographic handshake takes too long (this is a [net.Error] timeout error) +// - [StatelessResetError]: when we receive a stateless reset +// - [VersionNegotiationError]: returned by the client, when there's no version overlap between the peers +type Conn struct { // Destination connection ID used during the handshake. // Used to check source connection ID on incoming packets. handshakeDestConnID protocol.ConnectionID @@ -133,7 +123,7 @@ type connection struct { largestRcvdAppData protocol.PacketNumber pathManagerOutgoing atomic.Pointer[pathManagerOutgoing] - streamsMap streamManager + streamsMap *streamsMap connIDManager *connIDManager connIDGenerator *connIDGenerator @@ -214,11 +204,22 @@ type connection struct { logger utils.Logger } -var ( - _ Connection = &connection{} - _ EarlyConnection = &connection{} - _ streamSender = &connection{} -) +var _ streamSender = &Conn{} + +type connTestHooks struct { + run func() error + earlyConnReady func() <-chan struct{} + context func() context.Context + handshakeComplete func() <-chan struct{} + closeWithTransportError func(TransportErrorCode) + destroy func(error) + handlePacket func(receivedPacket) +} + +type wrappedConn struct { + testHooks *connTestHooks + *Conn +} var newConnection = func( ctx context.Context, @@ -240,8 +241,8 @@ var newConnection = func( tracer *logging.ConnectionTracer, logger utils.Logger, v protocol.Version, -) quicConn { - s := &connection{ +) *wrappedConn { + s := &Conn{ ctx: ctx, ctxCancel: ctxCancel, conn: conn, @@ -339,7 +340,7 @@ var newConnection = func( s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, s.receivedPacketHandler, s.datagramQueue, s.perspective) s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen) s.cryptoStreamManager = newCryptoStreamManager(s.initialStream, s.handshakeStream, s.oneRTTStream) - return s + return &wrappedConn{Conn: s} } // declare this as a variable, such that we can it mock it in the tests @@ -359,8 +360,8 @@ var newClientConnection = func( tracer *logging.ConnectionTracer, logger utils.Logger, v protocol.Version, -) quicConn { - s := &connection{ +) *wrappedConn { + s := &Conn{ conn: conn, config: conf, origDestConnID: destConnID, @@ -458,118 +459,118 @@ var newClientConnection = func( s.rttStats.SetInitialRTT(token.rtt) } } - return s + return &wrappedConn{Conn: s} } -func (s *connection) preSetup() { - s.largestRcvdAppData = protocol.InvalidPacketNumber - s.initialStream = newInitialCryptoStream(s.perspective == protocol.PerspectiveClient) - s.handshakeStream = newCryptoStream() - s.sendQueue = newSendQueue(s.conn) - s.retransmissionQueue = newRetransmissionQueue() - s.frameParser = *wire.NewFrameParser(s.config.EnableDatagrams) - s.rttStats = &utils.RTTStats{} - s.connFlowController = flowcontrol.NewConnectionFlowController( - protocol.ByteCount(s.config.InitialConnectionReceiveWindow), - protocol.ByteCount(s.config.MaxConnectionReceiveWindow), +func (c *Conn) preSetup() { + c.largestRcvdAppData = protocol.InvalidPacketNumber + c.initialStream = newInitialCryptoStream(c.perspective == protocol.PerspectiveClient) + c.handshakeStream = newCryptoStream() + c.sendQueue = newSendQueue(c.conn) + c.retransmissionQueue = newRetransmissionQueue() + c.frameParser = *wire.NewFrameParser(c.config.EnableDatagrams, false) + c.rttStats = &utils.RTTStats{} + c.connFlowController = flowcontrol.NewConnectionFlowController( + protocol.ByteCount(c.config.InitialConnectionReceiveWindow), + protocol.ByteCount(c.config.MaxConnectionReceiveWindow), func(size protocol.ByteCount) bool { - if s.config.AllowConnectionWindowIncrease == nil { + if c.config.AllowConnectionWindowIncrease == nil { return true } - return s.config.AllowConnectionWindowIncrease(s, uint64(size)) + return c.config.AllowConnectionWindowIncrease(c, uint64(size)) }, - s.rttStats, - s.logger, + c.rttStats, + c.logger, ) - s.earlyConnReadyChan = make(chan struct{}) - s.streamsMap = newStreamsMap( - s.ctx, - s, - s.queueControlFrame, - s.newFlowController, - uint64(s.config.MaxIncomingStreams), - uint64(s.config.MaxIncomingUniStreams), - s.perspective, + c.earlyConnReadyChan = make(chan struct{}) + c.streamsMap = newStreamsMap( + c.ctx, + c, + c.queueControlFrame, + c.newFlowController, + uint64(c.config.MaxIncomingStreams), + uint64(c.config.MaxIncomingUniStreams), + c.perspective, ) - s.framer = newFramer(s.connFlowController) - s.receivedPackets.Init(8) - s.notifyReceivedPacket = make(chan struct{}, 1) - s.closeChan = make(chan struct{}, 1) - s.sendingScheduled = make(chan struct{}, 1) - s.handshakeCompleteChan = make(chan struct{}) + c.framer = newFramer(c.connFlowController) + c.receivedPackets.Init(8) + c.notifyReceivedPacket = make(chan struct{}, 1) + c.closeChan = make(chan struct{}, 1) + c.sendingScheduled = make(chan struct{}, 1) + c.handshakeCompleteChan = make(chan struct{}) now := time.Now() - s.lastPacketReceivedTime = now - s.creationTime = now + c.lastPacketReceivedTime = now + c.creationTime = now - s.datagramQueue = newDatagramQueue(s.scheduleSending, s.logger) - s.connState.Version = s.version + c.datagramQueue = newDatagramQueue(c.scheduleSending, c.logger) + c.connState.Version = c.version } // run the connection main loop -func (s *connection) run() (err error) { - defer func() { s.ctxCancel(err) }() +func (c *Conn) run() (err error) { + defer func() { c.ctxCancel(err) }() defer func() { // drain queued packets that will never be processed - s.receivedPacketMx.Lock() - defer s.receivedPacketMx.Unlock() + c.receivedPacketMx.Lock() + defer c.receivedPacketMx.Unlock() - for !s.receivedPackets.Empty() { - p := s.receivedPackets.PopFront() + for !c.receivedPackets.Empty() { + p := c.receivedPackets.PopFront() p.buffer.Decrement() p.buffer.MaybeRelease() } }() - s.timer = *newTimer() + c.timer = *newTimer() - if err := s.cryptoStreamHandler.StartHandshake(s.ctx); err != nil { + if err := c.cryptoStreamHandler.StartHandshake(c.ctx); err != nil { return err } - if err := s.handleHandshakeEvents(time.Now()); err != nil { + if err := c.handleHandshakeEvents(time.Now()); err != nil { return err } go func() { - if err := s.sendQueue.Run(); err != nil { - s.destroyImpl(err) + if err := c.sendQueue.Run(); err != nil { + c.destroyImpl(err) } }() - if s.perspective == protocol.PerspectiveClient { - s.scheduleSending() // so the ClientHello actually gets sent + if c.perspective == protocol.PerspectiveClient { + c.scheduleSending() // so the ClientHello actually gets sent } var sendQueueAvailable <-chan struct{} runLoop: for { - if s.framer.QueuedTooManyControlFrames() { - s.setCloseError(&closeError{err: &qerr.TransportError{ErrorCode: InternalError}}) + if c.framer.QueuedTooManyControlFrames() { + c.setCloseError(&closeError{err: &qerr.TransportError{ErrorCode: InternalError}}) break runLoop } // Close immediately if requested select { - case <-s.closeChan: + case <-c.closeChan: break runLoop default: } // no need to set a timer if we can send packets immediately - if s.pacingDeadline != deadlineSendImmediately { - s.maybeResetTimer() + if c.pacingDeadline != deadlineSendImmediately { + c.maybeResetTimer() } // 1st: handle undecryptable packets, if any. // This can only occur before completion of the handshake. - if len(s.undecryptablePacketsToProcess) > 0 { + if len(c.undecryptablePacketsToProcess) > 0 { var processedUndecryptablePacket bool - queue := s.undecryptablePacketsToProcess - s.undecryptablePacketsToProcess = nil + queue := c.undecryptablePacketsToProcess + c.undecryptablePacketsToProcess = nil for _, p := range queue { - processed, err := s.handleOnePacket(p) + processed, err := c.handleOnePacket(p) if err != nil { - s.setCloseError(&closeError{err: err}) + c.setCloseError(&closeError{err: err}) break runLoop } if processed { @@ -583,16 +584,16 @@ runLoop: } // 2nd: receive packets. - processed, err := s.handlePackets() // don't check receivedPackets.Len() in the run loop to avoid locking the mutex + processed, err := c.handlePackets() // don't check receivedPackets.Len() in the run loop to avoid locking the mutex if err != nil { - s.setCloseError(&closeError{err: err}) + c.setCloseError(&closeError{err: err}) break runLoop } // We don't need to wait for new events if: // * we processed packets: we probably need to send an ACK, and potentially more data // * the pacer allows us to send more packets immediately - shouldProceedImmediately := sendQueueAvailable == nil && (processed || s.pacingDeadline.Equal(deadlineSendImmediately)) + shouldProceedImmediately := sendQueueAvailable == nil && (processed || c.pacingDeadline.Equal(deadlineSendImmediately)) if !shouldProceedImmediately { // 3rd: wait for something to happen: // * closing of the connection @@ -601,16 +602,16 @@ runLoop: // * send queue available // * received packets select { - case <-s.closeChan: + case <-c.closeChan: break runLoop - case <-s.timer.Chan(): - s.timer.SetRead() - case <-s.sendingScheduled: + case <-c.timer.Chan(): + c.timer.SetRead() + case <-c.sendingScheduled: case <-sendQueueAvailable: - case <-s.notifyReceivedPacket: - wasProcessed, err := s.handlePackets() + case <-c.notifyReceivedPacket: + wasProcessed, err := c.handlePackets() if err != nil { - s.setCloseError(&closeError{err: err}) + c.setCloseError(&closeError{err: err}) break runLoop } // if we processed any undecryptable packets, jump to the resetting of the timers directly @@ -623,256 +624,255 @@ runLoop: // Check for loss detection timeout. // This could cause packets to be declared lost, and retransmissions to be enqueued. now := time.Now() - if timeout := s.sentPacketHandler.GetLossDetectionTimeout(); !timeout.IsZero() && timeout.Before(now) { - if err := s.sentPacketHandler.OnLossDetectionTimeout(now); err != nil { - s.setCloseError(&closeError{err: err}) + if timeout := c.sentPacketHandler.GetLossDetectionTimeout(); !timeout.IsZero() && timeout.Before(now) { + if err := c.sentPacketHandler.OnLossDetectionTimeout(now); err != nil { + c.setCloseError(&closeError{err: err}) break runLoop } } - if keepAliveTime := s.nextKeepAliveTime(); !keepAliveTime.IsZero() && !now.Before(keepAliveTime) { + if keepAliveTime := c.nextKeepAliveTime(); !keepAliveTime.IsZero() && !now.Before(keepAliveTime) { // send a PING frame since there is no activity in the connection - s.logger.Debugf("Sending a keep-alive PING to keep the connection alive.") - s.framer.QueueControlFrame(&wire.PingFrame{}) - s.keepAlivePingSent = true - } else if !s.handshakeComplete && now.Sub(s.creationTime) >= s.config.handshakeTimeout() { - s.destroyImpl(qerr.ErrHandshakeTimeout) + c.logger.Debugf("Sending a keep-alive PING to keep the connection alive.") + c.framer.QueueControlFrame(&wire.PingFrame{}) + c.keepAlivePingSent = true + } else if !c.handshakeComplete && now.Sub(c.creationTime) >= c.config.handshakeTimeout() { + c.destroyImpl(qerr.ErrHandshakeTimeout) break runLoop } else { - idleTimeoutStartTime := s.idleTimeoutStartTime() - if (!s.handshakeComplete && now.Sub(idleTimeoutStartTime) >= s.config.HandshakeIdleTimeout) || - (s.handshakeComplete && now.After(s.nextIdleTimeoutTime())) { - s.destroyImpl(qerr.ErrIdleTimeout) + idleTimeoutStartTime := c.idleTimeoutStartTime() + if (!c.handshakeComplete && now.Sub(idleTimeoutStartTime) >= c.config.HandshakeIdleTimeout) || + (c.handshakeComplete && now.After(c.nextIdleTimeoutTime())) { + c.destroyImpl(qerr.ErrIdleTimeout) break runLoop } } - s.connIDGenerator.RemoveRetiredConnIDs(now) + c.connIDGenerator.RemoveRetiredConnIDs(now) - if s.perspective == protocol.PerspectiveClient { - pm := s.pathManagerOutgoing.Load() + if c.perspective == protocol.PerspectiveClient { + pm := c.pathManagerOutgoing.Load() if pm != nil { tr, ok := pm.ShouldSwitchPath() if ok { - s.switchToNewPath(tr, now) + c.switchToNewPath(tr, now) } } } - if s.sendQueue.WouldBlock() { + if c.sendQueue.WouldBlock() { // The send queue is still busy sending out packets. Wait until there's space to enqueue new packets. - sendQueueAvailable = s.sendQueue.Available() + sendQueueAvailable = c.sendQueue.Available() // Cancel the pacing timer, as we can't send any more packets until the send queue is available again. - s.pacingDeadline = time.Time{} + c.pacingDeadline = time.Time{} continue } - if s.closeErr.Load() != nil { + if c.closeErr.Load() != nil { break runLoop } - if err := s.triggerSending(now); err != nil { - s.setCloseError(&closeError{err: err}) + if err := c.triggerSending(now); err != nil { + c.setCloseError(&closeError{err: err}) break runLoop } - if s.sendQueue.WouldBlock() { + if c.sendQueue.WouldBlock() { // The send queue is still busy sending out packets. Wait until there's space to enqueue new packets. - sendQueueAvailable = s.sendQueue.Available() + sendQueueAvailable = c.sendQueue.Available() // Cancel the pacing timer, as we can't send any more packets until the send queue is available again. - s.pacingDeadline = time.Time{} + c.pacingDeadline = time.Time{} } else { sendQueueAvailable = nil } } - closeErr := s.closeErr.Load() - s.cryptoStreamHandler.Close() - s.sendQueue.Close() // close the send queue before sending the CONNECTION_CLOSE - s.handleCloseError(closeErr) - if s.tracer != nil && s.tracer.Close != nil { + closeErr := c.closeErr.Load() + c.cryptoStreamHandler.Close() + c.sendQueue.Close() // close the send queue before sending the CONNECTION_CLOSE + c.handleCloseError(closeErr) + if c.tracer != nil && c.tracer.Close != nil { if e := (&errCloseForRecreating{}); !errors.As(closeErr.err, &e) { - s.tracer.Close() + c.tracer.Close() } } - s.logger.Infof("Connection %s closed.", s.logID) - s.timer.Stop() + c.logger.Infof("Connection %s closed.", c.logID) + c.timer.Stop() return closeErr.err } // blocks until the early connection can be used -func (s *connection) earlyConnReady() <-chan struct{} { - return s.earlyConnReadyChan -} - -func (s *connection) HandshakeComplete() <-chan struct{} { - return s.handshakeCompleteChan +func (c *Conn) earlyConnReady() <-chan struct{} { + return c.earlyConnReadyChan } -func (s *connection) Context() context.Context { - return s.ctx +// Context returns a context that is cancelled when the connection is closed. +// The cancellation cause is set to the error that caused the connection to close. +func (c *Conn) Context() context.Context { + return c.ctx } -func (s *connection) supportsDatagrams() bool { - return s.peerParams.MaxDatagramFrameSize > 0 +func (c *Conn) supportsDatagrams() bool { + return c.peerParams.MaxDatagramFrameSize > 0 } -func (s *connection) ConnectionState() ConnectionState { - s.connStateMutex.Lock() - defer s.connStateMutex.Unlock() - cs := s.cryptoStreamHandler.ConnectionState() - s.connState.TLS = cs.ConnectionState - s.connState.Used0RTT = cs.Used0RTT - s.connState.GSO = s.conn.capabilities().GSO - return s.connState +// ConnectionState returns basic details about the QUIC connection. +func (c *Conn) ConnectionState() ConnectionState { + c.connStateMutex.Lock() + defer c.connStateMutex.Unlock() + cs := c.cryptoStreamHandler.ConnectionState() + c.connState.TLS = cs.ConnectionState + c.connState.Used0RTT = cs.Used0RTT + c.connState.GSO = c.conn.capabilities().GSO + return c.connState } // Time when the connection should time out -func (s *connection) nextIdleTimeoutTime() time.Time { - idleTimeout := max(s.idleTimeout, s.rttStats.PTO(true)*3) - return s.idleTimeoutStartTime().Add(idleTimeout) +func (c *Conn) nextIdleTimeoutTime() time.Time { + idleTimeout := max(c.idleTimeout, c.rttStats.PTO(true)*3) + return c.idleTimeoutStartTime().Add(idleTimeout) } // Time when the next keep-alive packet should be sent. // It returns a zero time if no keep-alive should be sent. -func (s *connection) nextKeepAliveTime() time.Time { - if s.config.KeepAlivePeriod == 0 || s.keepAlivePingSent { +func (c *Conn) nextKeepAliveTime() time.Time { + if c.config.KeepAlivePeriod == 0 || c.keepAlivePingSent { return time.Time{} } - keepAliveInterval := max(s.keepAliveInterval, s.rttStats.PTO(true)*3/2) - return s.lastPacketReceivedTime.Add(keepAliveInterval) + keepAliveInterval := max(c.keepAliveInterval, c.rttStats.PTO(true)*3/2) + return c.lastPacketReceivedTime.Add(keepAliveInterval) } -func (s *connection) maybeResetTimer() { +func (c *Conn) maybeResetTimer() { var deadline time.Time - if !s.handshakeComplete { - deadline = s.creationTime.Add(s.config.handshakeTimeout()) - if t := s.idleTimeoutStartTime().Add(s.config.HandshakeIdleTimeout); t.Before(deadline) { + if !c.handshakeComplete { + deadline = c.creationTime.Add(c.config.handshakeTimeout()) + if t := c.idleTimeoutStartTime().Add(c.config.HandshakeIdleTimeout); t.Before(deadline) { deadline = t } } else { - if keepAliveTime := s.nextKeepAliveTime(); !keepAliveTime.IsZero() { + if keepAliveTime := c.nextKeepAliveTime(); !keepAliveTime.IsZero() { deadline = keepAliveTime } else { - deadline = s.nextIdleTimeoutTime() + deadline = c.nextIdleTimeoutTime() } } - s.timer.SetTimer( + c.timer.SetTimer( deadline, - s.connIDGenerator.NextRetireTime(), - s.receivedPacketHandler.GetAlarmTimeout(), - s.sentPacketHandler.GetLossDetectionTimeout(), - s.pacingDeadline, + c.connIDGenerator.NextRetireTime(), + c.receivedPacketHandler.GetAlarmTimeout(), + c.sentPacketHandler.GetLossDetectionTimeout(), + c.pacingDeadline, ) } -func (s *connection) idleTimeoutStartTime() time.Time { - startTime := s.lastPacketReceivedTime - if t := s.firstAckElicitingPacketAfterIdleSentTime; t.After(startTime) { +func (c *Conn) idleTimeoutStartTime() time.Time { + startTime := c.lastPacketReceivedTime + if t := c.firstAckElicitingPacketAfterIdleSentTime; t.After(startTime) { startTime = t } return startTime } -func (s *connection) switchToNewPath(tr *Transport, now time.Time) { - initialPacketSize := protocol.ByteCount(s.config.InitialPacketSize) - s.sentPacketHandler.MigratedPath(now, initialPacketSize) +func (c *Conn) switchToNewPath(tr *Transport, now time.Time) { + initialPacketSize := protocol.ByteCount(c.config.InitialPacketSize) + c.sentPacketHandler.MigratedPath(now, initialPacketSize) maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) - if s.peerParams.MaxUDPPayloadSize > 0 && s.peerParams.MaxUDPPayloadSize < maxPacketSize { - maxPacketSize = s.peerParams.MaxUDPPayloadSize + if c.peerParams.MaxUDPPayloadSize > 0 && c.peerParams.MaxUDPPayloadSize < maxPacketSize { + maxPacketSize = c.peerParams.MaxUDPPayloadSize } - s.mtuDiscoverer.Reset(now, initialPacketSize, maxPacketSize) - s.conn = newSendConn(tr.conn, s.conn.RemoteAddr(), packetInfo{}, utils.DefaultLogger) // TODO: find a better way - s.sendQueue.Close() - s.sendQueue = newSendQueue(s.conn) + c.mtuDiscoverer.Reset(now, initialPacketSize, maxPacketSize) + c.conn = newSendConn(tr.conn, c.conn.RemoteAddr(), packetInfo{}, utils.DefaultLogger) // TODO: find a better way + c.sendQueue.Close() + c.sendQueue = newSendQueue(c.conn) go func() { - if err := s.sendQueue.Run(); err != nil { - s.destroyImpl(err) + if err := c.sendQueue.Run(); err != nil { + c.destroyImpl(err) } }() } -func (s *connection) handleHandshakeComplete(now time.Time) error { - defer close(s.handshakeCompleteChan) +func (c *Conn) handleHandshakeComplete(now time.Time) error { + defer close(c.handshakeCompleteChan) // Once the handshake completes, we have derived 1-RTT keys. // There's no point in queueing undecryptable packets for later decryption anymore. - s.undecryptablePackets = nil + c.undecryptablePackets = nil - s.connIDManager.SetHandshakeComplete() - s.connIDGenerator.SetHandshakeComplete(now.Add(3 * s.rttStats.PTO(false))) + c.connIDManager.SetHandshakeComplete() + c.connIDGenerator.SetHandshakeComplete(now.Add(3 * c.rttStats.PTO(false))) - if s.tracer != nil && s.tracer.ChoseALPN != nil { - s.tracer.ChoseALPN(s.cryptoStreamHandler.ConnectionState().NegotiatedProtocol) + if c.tracer != nil && c.tracer.ChoseALPN != nil { + c.tracer.ChoseALPN(c.cryptoStreamHandler.ConnectionState().NegotiatedProtocol) } // The server applies transport parameters right away, but the client side has to wait for handshake completion. // During a 0-RTT connection, the client is only allowed to use the new transport parameters for 1-RTT packets. - if s.perspective == protocol.PerspectiveClient { - s.applyTransportParameters() + if c.perspective == protocol.PerspectiveClient { + c.applyTransportParameters() return nil } // All these only apply to the server side. - if err := s.handleHandshakeConfirmed(now); err != nil { + if err := c.handleHandshakeConfirmed(now); err != nil { return err } - ticket, err := s.cryptoStreamHandler.GetSessionTicket() + ticket, err := c.cryptoStreamHandler.GetSessionTicket() if err != nil { return err } if ticket != nil { // may be nil if session tickets are disabled via tls.Config.SessionTicketsDisabled - s.oneRTTStream.Write(ticket) - for s.oneRTTStream.HasData() { - if cf := s.oneRTTStream.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil { - s.queueControlFrame(cf) + c.oneRTTStream.Write(ticket) + for c.oneRTTStream.HasData() { + if cf := c.oneRTTStream.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil { + c.queueControlFrame(cf) } } } - token, err := s.tokenGenerator.NewToken(s.conn.RemoteAddr(), s.rttStats.SmoothedRTT()) + token, err := c.tokenGenerator.NewToken(c.conn.RemoteAddr(), c.rttStats.SmoothedRTT()) if err != nil { return err } - s.queueControlFrame(&wire.NewTokenFrame{Token: token}) - s.queueControlFrame(&wire.HandshakeDoneFrame{}) + c.queueControlFrame(&wire.NewTokenFrame{Token: token}) + c.queueControlFrame(&wire.HandshakeDoneFrame{}) return nil } -func (s *connection) handleHandshakeConfirmed(now time.Time) error { - if err := s.dropEncryptionLevel(protocol.EncryptionHandshake, now); err != nil { +func (c *Conn) handleHandshakeConfirmed(now time.Time) error { + if err := c.dropEncryptionLevel(protocol.EncryptionHandshake, now); err != nil { return err } - s.handshakeConfirmed = true - s.cryptoStreamHandler.SetHandshakeConfirmed() + c.handshakeConfirmed = true + c.cryptoStreamHandler.SetHandshakeConfirmed() - if !s.config.DisablePathMTUDiscovery && s.conn.capabilities().DF { - s.mtuDiscoverer.Start(now) + if !c.config.DisablePathMTUDiscovery && c.conn.capabilities().DF { + c.mtuDiscoverer.Start(now) } return nil } -func (s *connection) handlePackets() (wasProcessed bool, _ error) { +func (c *Conn) handlePackets() (wasProcessed bool, _ error) { // Now process all packets in the receivedPackets channel. // Limit the number of packets to the length of the receivedPackets channel, // so we eventually get a chance to send out an ACK when receiving a lot of packets. - s.receivedPacketMx.Lock() - numPackets := s.receivedPackets.Len() + c.receivedPacketMx.Lock() + numPackets := c.receivedPackets.Len() if numPackets == 0 { - s.receivedPacketMx.Unlock() + c.receivedPacketMx.Unlock() return false, nil } var hasMorePackets bool for i := 0; i < numPackets; i++ { if i > 0 { - s.receivedPacketMx.Lock() + c.receivedPacketMx.Lock() } - p := s.receivedPackets.PopFront() - hasMorePackets = !s.receivedPackets.Empty() - s.receivedPacketMx.Unlock() + p := c.receivedPackets.PopFront() + hasMorePackets = !c.receivedPackets.Empty() + c.receivedPacketMx.Unlock() - processed, err := s.handleOnePacket(p) + processed, err := c.handleOnePacket(p) if err != nil { return false, err } @@ -883,24 +883,24 @@ func (s *connection) handlePackets() (wasProcessed bool, _ error) { break } // only process a single packet at a time before handshake completion - if !s.handshakeComplete { + if !c.handshakeComplete { break } } if hasMorePackets { select { - case s.notifyReceivedPacket <- struct{}{}: + case c.notifyReceivedPacket <- struct{}{}: default: } } return wasProcessed, nil } -func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) { - s.sentPacketHandler.ReceivedBytes(rp.Size(), rp.rcvTime) +func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) { + c.sentPacketHandler.ReceivedBytes(rp.Size(), rp.rcvTime) if wire.IsVersionNegotiationPacket(rp.data) { - s.handleVersionNegotiationPacket(rp) + c.handleVersionNegotiationPacket(rp) return false, nil } @@ -913,19 +913,19 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er p = *(p.Clone()) p.data = data - destConnID, err := wire.ParseConnectionID(p.data, s.srcConnIDLen) + destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen) if err != nil { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropHeaderParseError) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropHeaderParseError) } - s.logger.Debugf("error parsing packet, couldn't parse connection ID: %s", err) + c.logger.Debugf("error parsing packet, couldn't parse connection ID: %s", err) break } if destConnID != lastConnID { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnknownConnectionID) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnknownConnectionID) } - s.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", destConnID, lastConnID) + c.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", destConnID, lastConnID) break } } @@ -933,23 +933,23 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er if wire.IsLongHeaderPacket(p.data[0]) { hdr, packetData, rest, err := wire.ParsePacket(p.data) if err != nil { - if s.tracer != nil && s.tracer.DroppedPacket != nil { + if c.tracer != nil && c.tracer.DroppedPacket != nil { dropReason := logging.PacketDropHeaderParseError if err == wire.ErrUnsupportedVersion { dropReason = logging.PacketDropUnsupportedVersion } - s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), dropReason) + c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), dropReason) } - s.logger.Debugf("error parsing packet: %s", err) + c.logger.Debugf("error parsing packet: %s", err) break } lastConnID = hdr.DestConnectionID - if hdr.Version != s.version { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedVersion) + if hdr.Version != c.version { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedVersion) } - s.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, s.version) + c.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, c.version) break } @@ -959,13 +959,13 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er counter++ // only log if this actually a coalesced packet - if s.logger.Debug() && (counter > 1 || len(rest) > 0) { - s.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packetData), len(rest)) + if c.logger.Debug() && (counter > 1 || len(rest) > 0) { + c.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packetData), len(rest)) } p.data = packetData - processed, err := s.handleLongHeaderPacket(p, hdr) + processed, err := c.handleLongHeaderPacket(p, hdr) if err != nil { return false, err } @@ -977,7 +977,7 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er if counter > 0 { p.buffer.Split() } - processed, err := s.handleShortHeaderPacket(p, counter > 0) + processed, err := c.handleShortHeaderPacket(p, counter > 0) if err != nil { return false, err } @@ -992,7 +992,7 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er return wasProcessed, nil } -func (s *connection) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasProcessed bool, _ error) { +func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasProcessed bool, _ error) { var wasQueued bool defer func() { @@ -1002,12 +1002,12 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) } }() - destConnID, err := wire.ParseConnectionID(p.data, s.srcConnIDLen) + destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen) if err != nil { - s.tracer.DroppedPacket(logging.PacketType1RTT, protocol.InvalidPacketNumber, protocol.ByteCount(len(p.data)), logging.PacketDropHeaderParseError) + c.tracer.DroppedPacket(logging.PacketType1RTT, protocol.InvalidPacketNumber, protocol.ByteCount(len(p.data)), logging.PacketDropHeaderParseError) return false, nil } - pn, pnLen, keyPhase, data, err := s.unpacker.UnpackShortHeader(p.rcvTime, p.data) + pn, pnLen, keyPhase, data, err := c.unpacker.UnpackShortHeader(p.rcvTime, p.data) if err != nil { // Stateless reset packets (see RFC 9000, section 10.3): // * fill the entire UDP datagram (i.e. they cannot be part of a coalesced packet) @@ -1016,32 +1016,32 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) // * are at least 21 bytes long if !isCoalesced && len(p.data) >= protocol.MinReceivedStatelessResetSize && p.data[0]&0b11000000 == 0b01000000 { token := protocol.StatelessResetToken(p.data[len(p.data)-16:]) - if s.connIDManager.IsActiveStatelessResetToken(token) { + if c.connIDManager.IsActiveStatelessResetToken(token) { return false, &StatelessResetError{} } } - wasQueued, err = s.handleUnpackError(err, p, logging.PacketType1RTT) + wasQueued, err = c.handleUnpackError(err, p, logging.PacketType1RTT) return false, err } - s.largestRcvdAppData = max(s.largestRcvdAppData, pn) + c.largestRcvdAppData = max(c.largestRcvdAppData, pn) - if s.logger.Debug() { - s.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, 1-RTT", pn, p.Size(), destConnID) - wire.LogShortHeader(s.logger, destConnID, pn, pnLen, keyPhase) + if c.logger.Debug() { + c.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, 1-RTT", pn, p.Size(), destConnID) + wire.LogShortHeader(c.logger, destConnID, pn, pnLen, keyPhase) } - if s.receivedPacketHandler.IsPotentiallyDuplicate(pn, protocol.Encryption1RTT) { - s.logger.Debugf("Dropping (potentially) duplicate packet.") - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketType1RTT, pn, p.Size(), logging.PacketDropDuplicate) + if c.receivedPacketHandler.IsPotentiallyDuplicate(pn, protocol.Encryption1RTT) { + c.logger.Debugf("Dropping (potentially) duplicate packet.") + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketType1RTT, pn, p.Size(), logging.PacketDropDuplicate) } return false, nil } var log func([]logging.Frame) - if s.tracer != nil && s.tracer.ReceivedShortHeaderPacket != nil { + if c.tracer != nil && c.tracer.ReceivedShortHeaderPacket != nil { log = func(frames []logging.Frame) { - s.tracer.ReceivedShortHeaderPacket( + c.tracer.ReceivedShortHeaderPacket( &logging.ShortHeader{ DestConnectionID: destConnID, PacketNumber: pn, @@ -1054,59 +1054,59 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) ) } } - isNonProbing, pathChallenge, err := s.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log) + isNonProbing, pathChallenge, err := c.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log) if err != nil { return false, err } // In RFC 9000, only the client can migrate between paths. - if s.perspective == protocol.PerspectiveClient { + if c.perspective == protocol.PerspectiveClient { return true, nil } - if addrsEqual(p.remoteAddr, s.RemoteAddr()) { + if addrsEqual(p.remoteAddr, c.RemoteAddr()) { return true, nil } var shouldSwitchPath bool - if s.pathManager == nil { - s.pathManager = newPathManager( - s.connIDManager.GetConnIDForPath, - s.connIDManager.RetireConnIDForPath, - s.logger, + if c.pathManager == nil { + c.pathManager = newPathManager( + c.connIDManager.GetConnIDForPath, + c.connIDManager.RetireConnIDForPath, + c.logger, ) } - destConnID, frames, shouldSwitchPath := s.pathManager.HandlePacket(p.remoteAddr, p.rcvTime, pathChallenge, isNonProbing) + destConnID, frames, shouldSwitchPath := c.pathManager.HandlePacket(p.remoteAddr, p.rcvTime, pathChallenge, isNonProbing) if len(frames) > 0 { - probe, buf, err := s.packer.PackPathProbePacket(destConnID, frames, s.version) + probe, buf, err := c.packer.PackPathProbePacket(destConnID, frames, c.version) if err != nil { return true, err } - s.logger.Debugf("sending path probe packet to %s", p.remoteAddr) - s.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) - s.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime) - s.sendQueue.SendProbe(buf, p.remoteAddr) + c.logger.Debugf("sending path probe packet to %s", p.remoteAddr) + c.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) + c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime) + c.sendQueue.SendProbe(buf, p.remoteAddr) } // We only switch paths in response to the highest-numbered non-probing packet, // see section 9.3 of RFC 9000. - if !shouldSwitchPath || pn != s.largestRcvdAppData { + if !shouldSwitchPath || pn != c.largestRcvdAppData { return true, nil } - s.pathManager.SwitchToPath(p.remoteAddr) - s.sentPacketHandler.MigratedPath(p.rcvTime, protocol.ByteCount(s.config.InitialPacketSize)) + c.pathManager.SwitchToPath(p.remoteAddr) + c.sentPacketHandler.MigratedPath(p.rcvTime, protocol.ByteCount(c.config.InitialPacketSize)) maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) - if s.peerParams.MaxUDPPayloadSize > 0 && s.peerParams.MaxUDPPayloadSize < maxPacketSize { - maxPacketSize = s.peerParams.MaxUDPPayloadSize + if c.peerParams.MaxUDPPayloadSize > 0 && c.peerParams.MaxUDPPayloadSize < maxPacketSize { + maxPacketSize = c.peerParams.MaxUDPPayloadSize } - s.mtuDiscoverer.Reset( + c.mtuDiscoverer.Reset( p.rcvTime, - protocol.ByteCount(s.config.InitialPacketSize), + protocol.ByteCount(c.config.InitialPacketSize), maxPacketSize, ) - s.conn.ChangeRemoteAddr(p.remoteAddr, p.info) + c.conn.ChangeRemoteAddr(p.remoteAddr, p.info) return true, nil } -func (s *connection) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) (wasProcessed bool, _ error) { +func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) (wasProcessed bool, _ error) { var wasQueued bool defer func() { @@ -1117,63 +1117,63 @@ func (s *connection) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) }() if hdr.Type == protocol.PacketTypeRetry { - return s.handleRetryPacket(hdr, p.data, p.rcvTime), nil + return c.handleRetryPacket(hdr, p.data, p.rcvTime), nil } // The server can change the source connection ID with the first Handshake packet. // After this, all packets with a different source connection have to be ignored. - if s.receivedFirstPacket && hdr.Type == protocol.PacketTypeInitial && hdr.SrcConnectionID != s.handshakeDestConnID { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeInitial, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnknownConnectionID) + if c.receivedFirstPacket && hdr.Type == protocol.PacketTypeInitial && hdr.SrcConnectionID != c.handshakeDestConnID { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeInitial, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnknownConnectionID) } - s.logger.Debugf("Dropping Initial packet (%d bytes) with unexpected source connection ID: %s (expected %s)", p.Size(), hdr.SrcConnectionID, s.handshakeDestConnID) + c.logger.Debugf("Dropping Initial packet (%d bytes) with unexpected source connection ID: %s (expected %s)", p.Size(), hdr.SrcConnectionID, c.handshakeDestConnID) return false, nil } // drop 0-RTT packets, if we are a client - if s.perspective == protocol.PerspectiveClient && hdr.Type == protocol.PacketType0RTT { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketType0RTT, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket) + if c.perspective == protocol.PerspectiveClient && hdr.Type == protocol.PacketType0RTT { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketType0RTT, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket) } return false, nil } - packet, err := s.unpacker.UnpackLongHeader(hdr, p.data) + packet, err := c.unpacker.UnpackLongHeader(hdr, p.data) if err != nil { - wasQueued, err = s.handleUnpackError(err, p, logging.PacketTypeFromHeader(hdr)) + wasQueued, err = c.handleUnpackError(err, p, logging.PacketTypeFromHeader(hdr)) return false, err } - if s.logger.Debug() { - s.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, %s", packet.hdr.PacketNumber, p.Size(), hdr.DestConnectionID, packet.encryptionLevel) - packet.hdr.Log(s.logger) + if c.logger.Debug() { + c.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, %s", packet.hdr.PacketNumber, p.Size(), hdr.DestConnectionID, packet.encryptionLevel) + packet.hdr.Log(c.logger) } - if pn := packet.hdr.PacketNumber; s.receivedPacketHandler.IsPotentiallyDuplicate(pn, packet.encryptionLevel) { - s.logger.Debugf("Dropping (potentially) duplicate packet.") - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), pn, p.Size(), logging.PacketDropDuplicate) + if pn := packet.hdr.PacketNumber; c.receivedPacketHandler.IsPotentiallyDuplicate(pn, packet.encryptionLevel) { + c.logger.Debugf("Dropping (potentially) duplicate packet.") + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), pn, p.Size(), logging.PacketDropDuplicate) } return false, nil } - if err := s.handleUnpackedLongHeaderPacket(packet, p.ecn, p.rcvTime, p.Size()); err != nil { + if err := c.handleUnpackedLongHeaderPacket(packet, p.ecn, p.rcvTime, p.Size()); err != nil { return false, err } return true, nil } -func (s *connection) handleUnpackError(err error, p receivedPacket, pt logging.PacketType) (wasQueued bool, _ error) { +func (c *Conn) handleUnpackError(err error, p receivedPacket, pt logging.PacketType) (wasQueued bool, _ error) { switch err { case handshake.ErrKeysDropped: - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropKeyUnavailable) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropKeyUnavailable) } - s.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", pt, p.Size()) + c.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", pt, p.Size()) return false, nil case handshake.ErrKeysNotYetAvailable: // Sealer for this encryption level not yet available. // Try again later. - s.tryQueueingUndecryptablePacket(p, pt) + c.tryQueueingUndecryptablePacket(p, pt) return true, nil case wire.ErrInvalidReservedBits: return false, &qerr.TransportError{ @@ -1182,19 +1182,19 @@ func (s *connection) handleUnpackError(err error, p receivedPacket, pt logging.P } case handshake.ErrDecryptionFailed: // This might be a packet injected by an attacker. Drop it. - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropPayloadDecryptError) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropPayloadDecryptError) } - s.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", pt, p.Size(), err) + c.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", pt, p.Size(), err) return false, nil default: var headerErr *headerParseError if errors.As(err, &headerErr) { // This might be a packet injected by an attacker. Drop it. - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError) } - s.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", pt, p.Size(), err) + c.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", pt, p.Size(), err) return false, nil } // This is an error returned by the AEAD (other than ErrDecryptionFailed). @@ -1203,158 +1203,158 @@ func (s *connection) handleUnpackError(err error, p receivedPacket, pt logging.P } } -func (s *connection) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime time.Time) bool /* was this a valid Retry */ { - if s.perspective == protocol.PerspectiveServer { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) +func (c *Conn) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime time.Time) bool /* was this a valid Retry */ { + if c.perspective == protocol.PerspectiveServer { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) } - s.logger.Debugf("Ignoring Retry.") + c.logger.Debugf("Ignoring Retry.") return false } - if s.receivedFirstPacket { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) + if c.receivedFirstPacket { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) } - s.logger.Debugf("Ignoring Retry, since we already received a packet.") + c.logger.Debugf("Ignoring Retry, since we already received a packet.") return false } - destConnID := s.connIDManager.Get() + destConnID := c.connIDManager.Get() if hdr.SrcConnectionID == destConnID { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket) } - s.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.") + c.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.") return false } // If a token is already set, this means that we already received a Retry from the server. // Ignore this Retry packet. - if s.receivedRetry { - s.logger.Debugf("Ignoring Retry, since a Retry was already received.") + if c.receivedRetry { + c.logger.Debugf("Ignoring Retry, since a Retry was already received.") return false } tag := handshake.GetRetryIntegrityTag(data[:len(data)-16], destConnID, hdr.Version) if !bytes.Equal(data[len(data)-16:], tag[:]) { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropPayloadDecryptError) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropPayloadDecryptError) } - s.logger.Debugf("Ignoring spoofed Retry. Integrity Tag doesn't match.") + c.logger.Debugf("Ignoring spoofed Retry. Integrity Tag doesn't match.") return false } newDestConnID := hdr.SrcConnectionID - s.receivedRetry = true - s.sentPacketHandler.ResetForRetry(rcvTime) - s.handshakeDestConnID = newDestConnID - s.retrySrcConnID = &newDestConnID - s.cryptoStreamHandler.ChangeConnectionID(newDestConnID) - s.packer.SetToken(hdr.Token) - s.connIDManager.ChangeInitialConnID(newDestConnID) + c.receivedRetry = true + c.sentPacketHandler.ResetForRetry(rcvTime) + c.handshakeDestConnID = newDestConnID + c.retrySrcConnID = &newDestConnID + c.cryptoStreamHandler.ChangeConnectionID(newDestConnID) + c.packer.SetToken(hdr.Token) + c.connIDManager.ChangeInitialConnID(newDestConnID) - if s.logger.Debug() { - s.logger.Debugf("<- Received Retry:") - (&wire.ExtendedHeader{Header: *hdr}).Log(s.logger) - s.logger.Debugf("Switching destination connection ID to: %s", hdr.SrcConnectionID) + if c.logger.Debug() { + c.logger.Debugf("<- Received Retry:") + (&wire.ExtendedHeader{Header: *hdr}).Log(c.logger) + c.logger.Debugf("Switching destination connection ID to: %s", hdr.SrcConnectionID) } - if s.tracer != nil && s.tracer.ReceivedRetry != nil { - s.tracer.ReceivedRetry(hdr) + if c.tracer != nil && c.tracer.ReceivedRetry != nil { + c.tracer.ReceivedRetry(hdr) } - s.scheduleSending() + c.scheduleSending() return true } -func (s *connection) handleVersionNegotiationPacket(p receivedPacket) { - if s.perspective == protocol.PerspectiveServer || // servers never receive version negotiation packets - s.receivedFirstPacket || s.versionNegotiated { // ignore delayed / duplicated version negotiation packets - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket) +func (c *Conn) handleVersionNegotiationPacket(p receivedPacket) { + if c.perspective == protocol.PerspectiveServer || // servers never receive version negotiation packets + c.receivedFirstPacket || c.versionNegotiated { // ignore delayed / duplicated version negotiation packets + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket) } return } src, dest, supportedVersions, err := wire.ParseVersionNegotiationPacket(p.data) if err != nil { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError) + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError) } - s.logger.Debugf("Error parsing Version Negotiation packet: %s", err) + c.logger.Debugf("Error parsing Version Negotiation packet: %s", err) return } - if slices.Contains(supportedVersions, s.version) { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedVersion) + if slices.Contains(supportedVersions, c.version) { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedVersion) } // The Version Negotiation packet contains the version that we offered. // This might be a packet sent by an attacker, or it was corrupted. return } - s.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", supportedVersions) - if s.tracer != nil && s.tracer.ReceivedVersionNegotiationPacket != nil { - s.tracer.ReceivedVersionNegotiationPacket(dest, src, supportedVersions) + c.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", supportedVersions) + if c.tracer != nil && c.tracer.ReceivedVersionNegotiationPacket != nil { + c.tracer.ReceivedVersionNegotiationPacket(dest, src, supportedVersions) } - newVersion, ok := protocol.ChooseSupportedVersion(s.config.Versions, supportedVersions) + newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, supportedVersions) if !ok { - s.destroyImpl(&VersionNegotiationError{ - Ours: s.config.Versions, + c.destroyImpl(&VersionNegotiationError{ + Ours: c.config.Versions, Theirs: supportedVersions, }) - s.logger.Infof("No compatible QUIC version found.") + c.logger.Infof("No compatible QUIC version found.") return } - if s.tracer != nil && s.tracer.NegotiatedVersion != nil { - s.tracer.NegotiatedVersion(newVersion, s.config.Versions, supportedVersions) + if c.tracer != nil && c.tracer.NegotiatedVersion != nil { + c.tracer.NegotiatedVersion(newVersion, c.config.Versions, supportedVersions) } - s.logger.Infof("Switching to QUIC version %s.", newVersion) - nextPN, _ := s.sentPacketHandler.PeekPacketNumber(protocol.EncryptionInitial) - s.destroyImpl(&errCloseForRecreating{ + c.logger.Infof("Switching to QUIC version %s.", newVersion) + nextPN, _ := c.sentPacketHandler.PeekPacketNumber(protocol.EncryptionInitial) + c.destroyImpl(&errCloseForRecreating{ nextPacketNumber: nextPN, nextVersion: newVersion, }) } -func (s *connection) handleUnpackedLongHeaderPacket( +func (c *Conn) handleUnpackedLongHeaderPacket( packet *unpackedPacket, ecn protocol.ECN, rcvTime time.Time, packetSize protocol.ByteCount, // only for logging ) error { - if !s.receivedFirstPacket { - s.receivedFirstPacket = true - if !s.versionNegotiated && s.tracer != nil && s.tracer.NegotiatedVersion != nil { + if !c.receivedFirstPacket { + c.receivedFirstPacket = true + if !c.versionNegotiated && c.tracer != nil && c.tracer.NegotiatedVersion != nil { var clientVersions, serverVersions []protocol.Version - switch s.perspective { + switch c.perspective { case protocol.PerspectiveClient: - clientVersions = s.config.Versions + clientVersions = c.config.Versions case protocol.PerspectiveServer: - serverVersions = s.config.Versions + serverVersions = c.config.Versions } - s.tracer.NegotiatedVersion(s.version, clientVersions, serverVersions) + c.tracer.NegotiatedVersion(c.version, clientVersions, serverVersions) } // The server can change the source connection ID with the first Handshake packet. - if s.perspective == protocol.PerspectiveClient && packet.hdr.SrcConnectionID != s.handshakeDestConnID { + if c.perspective == protocol.PerspectiveClient && packet.hdr.SrcConnectionID != c.handshakeDestConnID { cid := packet.hdr.SrcConnectionID - s.logger.Debugf("Received first packet. Switching destination connection ID to: %s", cid) - s.handshakeDestConnID = cid - s.connIDManager.ChangeInitialConnID(cid) + c.logger.Debugf("Received first packet. Switching destination connection ID to: %s", cid) + c.handshakeDestConnID = cid + c.connIDManager.ChangeInitialConnID(cid) } // We create the connection as soon as we receive the first packet from the client. // We do that before authenticating the packet. // That means that if the source connection ID was corrupted, // we might have created a connection with an incorrect source connection ID. // Once we authenticate the first packet, we need to update it. - if s.perspective == protocol.PerspectiveServer { - if packet.hdr.SrcConnectionID != s.handshakeDestConnID { - s.handshakeDestConnID = packet.hdr.SrcConnectionID - s.connIDManager.ChangeInitialConnID(packet.hdr.SrcConnectionID) + if c.perspective == protocol.PerspectiveServer { + if packet.hdr.SrcConnectionID != c.handshakeDestConnID { + c.handshakeDestConnID = packet.hdr.SrcConnectionID + c.connIDManager.ChangeInitialConnID(packet.hdr.SrcConnectionID) } - if s.tracer != nil && s.tracer.StartedConnection != nil { - s.tracer.StartedConnection( - s.conn.LocalAddr(), - s.conn.RemoteAddr(), + if c.tracer != nil && c.tracer.StartedConnection != nil { + c.tracer.StartedConnection( + c.conn.LocalAddr(), + c.conn.RemoteAddr(), packet.hdr.SrcConnectionID, packet.hdr.DestConnectionID, ) @@ -1362,37 +1362,37 @@ func (s *connection) handleUnpackedLongHeaderPacket( } } - if s.perspective == protocol.PerspectiveServer && packet.encryptionLevel == protocol.EncryptionHandshake && - !s.droppedInitialKeys { + if c.perspective == protocol.PerspectiveServer && packet.encryptionLevel == protocol.EncryptionHandshake && + !c.droppedInitialKeys { // On the server side, Initial keys are dropped as soon as the first Handshake packet is received. // See Section 4.9.1 of RFC 9001. - if err := s.dropEncryptionLevel(protocol.EncryptionInitial, rcvTime); err != nil { + if err := c.dropEncryptionLevel(protocol.EncryptionInitial, rcvTime); err != nil { return err } } - s.lastPacketReceivedTime = rcvTime - s.firstAckElicitingPacketAfterIdleSentTime = time.Time{} - s.keepAlivePingSent = false + c.lastPacketReceivedTime = rcvTime + c.firstAckElicitingPacketAfterIdleSentTime = time.Time{} + c.keepAlivePingSent = false if packet.hdr.Type == protocol.PacketType0RTT { - s.largestRcvdAppData = max(s.largestRcvdAppData, packet.hdr.PacketNumber) + c.largestRcvdAppData = max(c.largestRcvdAppData, packet.hdr.PacketNumber) } var log func([]logging.Frame) - if s.tracer != nil && s.tracer.ReceivedLongHeaderPacket != nil { + if c.tracer != nil && c.tracer.ReceivedLongHeaderPacket != nil { log = func(frames []logging.Frame) { - s.tracer.ReceivedLongHeaderPacket(packet.hdr, packetSize, ecn, frames) + c.tracer.ReceivedLongHeaderPacket(packet.hdr, packetSize, ecn, frames) } } - isAckEliciting, _, _, err := s.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime) + isAckEliciting, _, _, err := c.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime) if err != nil { return err } - return s.receivedPacketHandler.ReceivedPacket(packet.hdr.PacketNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting) + return c.receivedPacketHandler.ReceivedPacket(packet.hdr.PacketNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting) } -func (s *connection) handleUnpackedShortHeaderPacket( +func (c *Conn) handleUnpackedShortHeaderPacket( destConnID protocol.ConnectionID, pn protocol.PacketNumber, data []byte, @@ -1400,15 +1400,15 @@ func (s *connection) handleUnpackedShortHeaderPacket( rcvTime time.Time, log func([]logging.Frame), ) (isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) { - s.lastPacketReceivedTime = rcvTime - s.firstAckElicitingPacketAfterIdleSentTime = time.Time{} - s.keepAlivePingSent = false + c.lastPacketReceivedTime = rcvTime + c.firstAckElicitingPacketAfterIdleSentTime = time.Time{} + c.keepAlivePingSent = false - isAckEliciting, isNonProbing, pathChallenge, err := s.handleFrames(data, destConnID, protocol.Encryption1RTT, log, rcvTime) + isAckEliciting, isNonProbing, pathChallenge, err := c.handleFrames(data, destConnID, protocol.Encryption1RTT, log, rcvTime) if err != nil { return false, nil, err } - if err := s.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting); err != nil { + if err := c.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting); err != nil { return false, nil, err } return isNonProbing, pathChallenge, nil @@ -1416,7 +1416,7 @@ func (s *connection) handleUnpackedShortHeaderPacket( // handleFrames parses the frames, one after the other, and handles them. // It returns the last PATH_CHALLENGE frame contained in the packet, if any. -func (s *connection) handleFrames( +func (c *Conn) handleFrames( data []byte, destConnID protocol.ConnectionID, encLevel protocol.EncryptionLevel, @@ -1429,10 +1429,10 @@ func (s *connection) handleFrames( if log != nil { frames = make([]logging.Frame, 0, 4) } - handshakeWasComplete := s.handshakeComplete + handshakeWasComplete := c.handshakeComplete var handleErr error for len(data) > 0 { - l, frame, err := s.frameParser.ParseNext(data, encLevel, s.version) + l, frame, err := c.frameParser.ParseNext(data, encLevel, c.version) if err != nil { return false, false, nil, err } @@ -1454,7 +1454,7 @@ func (s *connection) handleFrames( if handleErr != nil { continue } - pc, err := s.handleFrame(frame, encLevel, destConnID, rcvTime) + pc, err := c.handleFrame(frame, encLevel, destConnID, rcvTime) if err != nil { if log == nil { return false, false, nil, err @@ -1478,61 +1478,61 @@ func (s *connection) handleFrames( // This ensures that we correctly handle the following case on the server side: // We receive a Handshake packet that contains the CRYPTO frame that allows us to complete the handshake, // and an ACK serialized after that CRYPTO frame. In this case, we still want to process the ACK frame. - if !handshakeWasComplete && s.handshakeComplete { - if err := s.handleHandshakeComplete(rcvTime); err != nil { + if !handshakeWasComplete && c.handshakeComplete { + if err := c.handleHandshakeComplete(rcvTime); err != nil { return false, false, nil, err } } return } -func (s *connection) handleFrame( +func (c *Conn) handleFrame( f wire.Frame, encLevel protocol.EncryptionLevel, destConnID protocol.ConnectionID, rcvTime time.Time, ) (pathChallenge *wire.PathChallengeFrame, _ error) { var err error - wire.LogFrame(s.logger, f, false) + wire.LogFrame(c.logger, f, false) switch frame := f.(type) { case *wire.CryptoFrame: - err = s.handleCryptoFrame(frame, encLevel, rcvTime) + err = c.handleCryptoFrame(frame, encLevel, rcvTime) case *wire.StreamFrame: - err = s.handleStreamFrame(frame, rcvTime) + err = c.streamsMap.HandleStreamFrame(frame, rcvTime) case *wire.AckFrame: - err = s.handleAckFrame(frame, encLevel, rcvTime) + err = c.handleAckFrame(frame, encLevel, rcvTime) case *wire.ConnectionCloseFrame: - err = s.handleConnectionCloseFrame(frame) + err = c.handleConnectionCloseFrame(frame) case *wire.ResetStreamFrame: - err = s.handleResetStreamFrame(frame, rcvTime) + err = c.streamsMap.HandleResetStreamFrame(frame, rcvTime) case *wire.MaxDataFrame: - s.handleMaxDataFrame(frame) + c.connFlowController.UpdateSendWindow(frame.MaximumData) case *wire.MaxStreamDataFrame: - err = s.handleMaxStreamDataFrame(frame) + err = c.streamsMap.HandleMaxStreamDataFrame(frame) case *wire.MaxStreamsFrame: - s.handleMaxStreamsFrame(frame) + c.streamsMap.HandleMaxStreamsFrame(frame) case *wire.DataBlockedFrame: case *wire.StreamDataBlockedFrame: - err = s.handleStreamDataBlockedFrame(frame) + err = c.streamsMap.HandleStreamDataBlockedFrame(frame) case *wire.StreamsBlockedFrame: case *wire.StopSendingFrame: - err = s.handleStopSendingFrame(frame) + err = c.streamsMap.HandleStopSendingFrame(frame) case *wire.PingFrame: case *wire.PathChallengeFrame: - s.handlePathChallengeFrame(frame) + c.handlePathChallengeFrame(frame) pathChallenge = frame case *wire.PathResponseFrame: - err = s.handlePathResponseFrame(frame) + err = c.handlePathResponseFrame(frame) case *wire.NewTokenFrame: - err = s.handleNewTokenFrame(frame) + err = c.handleNewTokenFrame(frame) case *wire.NewConnectionIDFrame: - err = s.handleNewConnectionIDFrame(frame) + err = c.connIDManager.Add(frame) case *wire.RetireConnectionIDFrame: - err = s.handleRetireConnectionIDFrame(rcvTime, frame, destConnID) + err = c.connIDGenerator.Retire(frame.SequenceNumber, destConnID, rcvTime.Add(3*c.rttStats.PTO(false))) case *wire.HandshakeDoneFrame: - err = s.handleHandshakeDoneFrame(rcvTime) + err = c.handleHandshakeDoneFrame(rcvTime) case *wire.DatagramFrame: - err = s.handleDatagramFrame(frame) + err = c.handleDatagramFrame(frame) default: err = fmt.Errorf("unexpected frame type: %s", reflect.ValueOf(&frame).Elem().Type().Name()) } @@ -1540,27 +1540,27 @@ func (s *connection) handleFrame( } // handlePacket is called by the server with a new packet -func (s *connection) handlePacket(p receivedPacket) { - s.receivedPacketMx.Lock() +func (c *Conn) handlePacket(p receivedPacket) { + c.receivedPacketMx.Lock() // Discard packets once the amount of queued packets is larger than // the channel size, protocol.MaxConnUnprocessedPackets - if s.receivedPackets.Len() >= protocol.MaxConnUnprocessedPackets { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention) + if c.receivedPackets.Len() >= protocol.MaxConnUnprocessedPackets { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention) } - s.receivedPacketMx.Unlock() + c.receivedPacketMx.Unlock() return } - s.receivedPackets.PushBack(p) - s.receivedPacketMx.Unlock() + c.receivedPackets.PushBack(p) + c.receivedPacketMx.Unlock() select { - case s.notifyReceivedPacket <- struct{}{}: + case c.notifyReceivedPacket <- struct{}{}: default: } } -func (s *connection) handleConnectionCloseFrame(frame *wire.ConnectionCloseFrame) error { +func (c *Conn) handleConnectionCloseFrame(frame *wire.ConnectionCloseFrame) error { if frame.IsApplicationError { return &qerr.ApplicationError{ Remote: true, @@ -1576,25 +1576,25 @@ func (s *connection) handleConnectionCloseFrame(frame *wire.ConnectionCloseFrame } } -func (s *connection) handleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { - if err := s.cryptoStreamManager.HandleCryptoFrame(frame, encLevel); err != nil { +func (c *Conn) handleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { + if err := c.cryptoStreamManager.HandleCryptoFrame(frame, encLevel); err != nil { return err } for { - data := s.cryptoStreamManager.GetCryptoData(encLevel) + data := c.cryptoStreamManager.GetCryptoData(encLevel) if data == nil { break } - if err := s.cryptoStreamHandler.HandleMessage(data, encLevel); err != nil { + if err := c.cryptoStreamHandler.HandleMessage(data, encLevel); err != nil { return err } } - return s.handleHandshakeEvents(rcvTime) + return c.handleHandshakeEvents(rcvTime) } -func (s *connection) handleHandshakeEvents(now time.Time) error { +func (c *Conn) handleHandshakeEvents(now time.Time) error { for { - ev := s.cryptoStreamHandler.NextEvent() + ev := c.cryptoStreamHandler.NextEvent() var err error switch ev.Kind { case handshake.EventNoEvent: @@ -1602,22 +1602,22 @@ func (s *connection) handleHandshakeEvents(now time.Time) error { case handshake.EventHandshakeComplete: // Don't call handleHandshakeComplete yet. // It's advantageous to process ACK frames that might be serialized after the CRYPTO frame first. - s.handshakeComplete = true + c.handshakeComplete = true case handshake.EventReceivedTransportParameters: - err = s.handleTransportParameters(ev.TransportParameters) + err = c.handleTransportParameters(ev.TransportParameters) case handshake.EventRestoredTransportParameters: - s.restoreTransportParameters(ev.TransportParameters) - close(s.earlyConnReadyChan) + c.restoreTransportParameters(ev.TransportParameters) + close(c.earlyConnReadyChan) case handshake.EventReceivedReadKeys: // queue all previously undecryptable packets - s.undecryptablePacketsToProcess = append(s.undecryptablePacketsToProcess, s.undecryptablePackets...) - s.undecryptablePackets = nil + c.undecryptablePacketsToProcess = append(c.undecryptablePacketsToProcess, c.undecryptablePackets...) + c.undecryptablePackets = nil case handshake.EventDiscard0RTTKeys: - err = s.dropEncryptionLevel(protocol.Encryption0RTT, now) + err = c.dropEncryptionLevel(protocol.Encryption0RTT, now) case handshake.EventWriteInitialData: - _, err = s.initialStream.Write(ev.Data) + _, err = c.initialStream.Write(ev.Data) case handshake.EventWriteHandshakeData: - _, err = s.handshakeStream.Write(ev.Data) + _, err = c.handshakeStream.Write(ev.Data) } if err != nil { return err @@ -1625,89 +1625,25 @@ func (s *connection) handleHandshakeEvents(now time.Time) error { } } -func (s *connection) handleStreamFrame(frame *wire.StreamFrame, rcvTime time.Time) error { - str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { // stream was already closed and garbage collected - return nil - } - return str.handleStreamFrame(frame, rcvTime) -} - -func (s *connection) handleMaxDataFrame(frame *wire.MaxDataFrame) { - s.connFlowController.UpdateSendWindow(frame.MaximumData) -} - -func (s *connection) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) error { - str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil +func (c *Conn) handlePathChallengeFrame(f *wire.PathChallengeFrame) { + if c.perspective == protocol.PerspectiveClient { + c.queueControlFrame(&wire.PathResponseFrame{Data: f.Data}) } - str.updateSendWindow(frame.MaximumStreamData) - return nil -} - -func (s *connection) handleStreamDataBlockedFrame(frame *wire.StreamDataBlockedFrame) error { - // We don't need to do anything in response to a STREAM_DATA_BLOCKED frame, - // but we need to make sure that the stream ID is valid. - _, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) - return err -} - -func (s *connection) handleMaxStreamsFrame(frame *wire.MaxStreamsFrame) { - s.streamsMap.HandleMaxStreamsFrame(frame) } -func (s *connection) handleResetStreamFrame(frame *wire.ResetStreamFrame, rcvTime time.Time) error { - str, err := s.streamsMap.GetOrOpenReceiveStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil - } - return str.handleResetStreamFrame(frame, rcvTime) -} - -func (s *connection) handleStopSendingFrame(frame *wire.StopSendingFrame) error { - str, err := s.streamsMap.GetOrOpenSendStream(frame.StreamID) - if err != nil { - return err - } - if str == nil { - // stream is closed and already garbage collected - return nil - } - str.handleStopSendingFrame(frame) - return nil -} - -func (s *connection) handlePathChallengeFrame(f *wire.PathChallengeFrame) { - if s.perspective == protocol.PerspectiveClient { - s.queueControlFrame(&wire.PathResponseFrame{Data: f.Data}) - } -} - -func (s *connection) handlePathResponseFrame(f *wire.PathResponseFrame) error { - switch s.perspective { +func (c *Conn) handlePathResponseFrame(f *wire.PathResponseFrame) error { + switch c.perspective { case protocol.PerspectiveClient: - return s.handlePathResponseFrameClient(f) + return c.handlePathResponseFrameClient(f) case protocol.PerspectiveServer: - return s.handlePathResponseFrameServer(f) + return c.handlePathResponseFrameServer(f) default: panic("unreachable") } } -func (s *connection) handlePathResponseFrameClient(f *wire.PathResponseFrame) error { - pm := s.pathManagerOutgoing.Load() +func (c *Conn) handlePathResponseFrameClient(f *wire.PathResponseFrame) error { + pm := c.pathManagerOutgoing.Load() if pm == nil { return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, @@ -1718,54 +1654,46 @@ func (s *connection) handlePathResponseFrameClient(f *wire.PathResponseFrame) er return nil } -func (s *connection) handlePathResponseFrameServer(f *wire.PathResponseFrame) error { - if s.pathManager == nil { +func (c *Conn) handlePathResponseFrameServer(f *wire.PathResponseFrame) error { + if c.pathManager == nil { // since we didn't send PATH_CHALLENGEs yet, we don't expect PATH_RESPONSEs return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, ErrorMessage: "unexpected PATH_RESPONSE frame", } } - s.pathManager.HandlePathResponseFrame(f) + c.pathManager.HandlePathResponseFrame(f) return nil } -func (s *connection) handleNewTokenFrame(frame *wire.NewTokenFrame) error { - if s.perspective == protocol.PerspectiveServer { +func (c *Conn) handleNewTokenFrame(frame *wire.NewTokenFrame) error { + if c.perspective == protocol.PerspectiveServer { return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, ErrorMessage: "received NEW_TOKEN frame from the client", } } - if s.config.TokenStore != nil { - s.config.TokenStore.Put(s.tokenStoreKey, &ClientToken{data: frame.Token, rtt: s.rttStats.SmoothedRTT()}) + if c.config.TokenStore != nil { + c.config.TokenStore.Put(c.tokenStoreKey, &ClientToken{data: frame.Token, rtt: c.rttStats.SmoothedRTT()}) } return nil } -func (s *connection) handleNewConnectionIDFrame(f *wire.NewConnectionIDFrame) error { - return s.connIDManager.Add(f) -} - -func (s *connection) handleRetireConnectionIDFrame(now time.Time, f *wire.RetireConnectionIDFrame, destConnID protocol.ConnectionID) error { - return s.connIDGenerator.Retire(f.SequenceNumber, destConnID, now.Add(3*s.rttStats.PTO(false))) -} - -func (s *connection) handleHandshakeDoneFrame(rcvTime time.Time) error { - if s.perspective == protocol.PerspectiveServer { +func (c *Conn) handleHandshakeDoneFrame(rcvTime time.Time) error { + if c.perspective == protocol.PerspectiveServer { return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, ErrorMessage: "received a HANDSHAKE_DONE frame", } } - if !s.handshakeConfirmed { - return s.handleHandshakeConfirmed(rcvTime) + if !c.handshakeConfirmed { + return c.handleHandshakeConfirmed(rcvTime) } return nil } -func (s *connection) handleAckFrame(frame *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { - acked1RTTPacket, err := s.sentPacketHandler.ReceivedAck(frame, encLevel, s.lastPacketReceivedTime) +func (c *Conn) handleAckFrame(frame *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) error { + acked1RTTPacket, err := c.sentPacketHandler.ReceivedAck(frame, encLevel, c.lastPacketReceivedTime) if err != nil { return err } @@ -1775,81 +1703,83 @@ func (s *connection) handleAckFrame(frame *wire.AckFrame, encLevel protocol.Encr // On the client side: If the packet acknowledged a 1-RTT packet, this confirms the handshake. // This is only possible if the ACK was sent in a 1-RTT packet. // This is an optimization over simply waiting for a HANDSHAKE_DONE frame, see section 4.1.2 of RFC 9001. - if s.perspective == protocol.PerspectiveClient && !s.handshakeConfirmed { - if err := s.handleHandshakeConfirmed(rcvTime); err != nil { + if c.perspective == protocol.PerspectiveClient && !c.handshakeConfirmed { + if err := c.handleHandshakeConfirmed(rcvTime); err != nil { return err } } // If one of the acknowledged packets was a Path MTU probe packet, this might have increased the Path MTU estimate. - if s.mtuDiscoverer != nil { - if mtu := s.mtuDiscoverer.CurrentSize(); mtu > protocol.ByteCount(s.currentMTUEstimate.Load()) { - s.currentMTUEstimate.Store(uint32(mtu)) - s.sentPacketHandler.SetMaxDatagramSize(mtu) + if c.mtuDiscoverer != nil { + if mtu := c.mtuDiscoverer.CurrentSize(); mtu > protocol.ByteCount(c.currentMTUEstimate.Load()) { + c.currentMTUEstimate.Store(uint32(mtu)) + c.sentPacketHandler.SetMaxDatagramSize(mtu) } } - return s.cryptoStreamHandler.SetLargest1RTTAcked(frame.LargestAcked()) + return c.cryptoStreamHandler.SetLargest1RTTAcked(frame.LargestAcked()) } -func (s *connection) handleDatagramFrame(f *wire.DatagramFrame) error { - if f.Length(s.version) > wire.MaxDatagramSize { +func (c *Conn) handleDatagramFrame(f *wire.DatagramFrame) error { + if f.Length(c.version) > wire.MaxDatagramSize { return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, ErrorMessage: "DATAGRAM frame too large", } } - s.datagramQueue.HandleDatagramFrame(f) + c.datagramQueue.HandleDatagramFrame(f) return nil } -func (s *connection) setCloseError(e *closeError) { - s.closeErr.CompareAndSwap(nil, e) +func (c *Conn) setCloseError(e *closeError) { + c.closeErr.CompareAndSwap(nil, e) select { - case s.closeChan <- struct{}{}: + case c.closeChan <- struct{}{}: default: } } // closeLocal closes the connection and send a CONNECTION_CLOSE containing the error -func (s *connection) closeLocal(e error) { - s.setCloseError(&closeError{err: e, immediate: false}) +func (c *Conn) closeLocal(e error) { + c.setCloseError(&closeError{err: e, immediate: false}) } // destroy closes the connection without sending the error on the wire -func (s *connection) destroy(e error) { - s.destroyImpl(e) - <-s.ctx.Done() +func (c *Conn) destroy(e error) { + c.destroyImpl(e) + <-c.ctx.Done() } -func (s *connection) destroyImpl(e error) { - s.setCloseError(&closeError{err: e, immediate: true}) +func (c *Conn) destroyImpl(e error) { + c.setCloseError(&closeError{err: e, immediate: true}) } -func (s *connection) CloseWithError(code ApplicationErrorCode, desc string) error { - s.closeLocal(&qerr.ApplicationError{ +// CloseWithError closes the connection with an error. +// The error string will be sent to the peer. +func (c *Conn) CloseWithError(code ApplicationErrorCode, desc string) error { + c.closeLocal(&qerr.ApplicationError{ ErrorCode: code, ErrorMessage: desc, }) - <-s.ctx.Done() + <-c.ctx.Done() return nil } -func (s *connection) closeWithTransportError(code TransportErrorCode) { - s.closeLocal(&qerr.TransportError{ErrorCode: code}) - <-s.ctx.Done() +func (c *Conn) closeWithTransportError(code TransportErrorCode) { + c.closeLocal(&qerr.TransportError{ErrorCode: code}) + <-c.ctx.Done() } -func (s *connection) handleCloseError(closeErr *closeError) { +func (c *Conn) handleCloseError(closeErr *closeError) { if closeErr.immediate { if nerr, ok := closeErr.err.(net.Error); ok && nerr.Timeout() { - s.logger.Errorf("Destroying connection: %s", closeErr.err) + c.logger.Errorf("Destroying connection: %s", closeErr.err) } else { - s.logger.Errorf("Destroying connection with error: %s", closeErr.err) + c.logger.Errorf("Destroying connection with error: %s", closeErr.err) } } else { if closeErr.err == nil { - s.logger.Infof("Closing connection.") + c.logger.Infof("Closing connection.") } else { - s.logger.Errorf("Closing connection with error: %s", closeErr.err) + c.logger.Errorf("Closing connection with error: %s", closeErr.err) } } @@ -1887,134 +1817,134 @@ func (s *connection) handleCloseError(closeErr *closeError) { } } - s.streamsMap.CloseWithError(e) - if s.datagramQueue != nil { - s.datagramQueue.CloseWithError(e) + c.streamsMap.CloseWithError(e) + if c.datagramQueue != nil { + c.datagramQueue.CloseWithError(e) } // In rare instances, the connection ID manager might switch to a new connection ID // when sending the CONNECTION_CLOSE frame. // The connection ID manager removes the active stateless reset token from the packet // handler map when it is closed, so we need to make sure that this happens last. - defer s.connIDManager.Close() + defer c.connIDManager.Close() - if s.tracer != nil && s.tracer.ClosedConnection != nil && !errors.As(e, &recreateErr) { - s.tracer.ClosedConnection(e) + if c.tracer != nil && c.tracer.ClosedConnection != nil && !errors.As(e, &recreateErr) { + c.tracer.ClosedConnection(e) } // If this is a remote close we're done here if isRemoteClose { - s.connIDGenerator.ReplaceWithClosed(nil, 3*s.rttStats.PTO(false)) + c.connIDGenerator.ReplaceWithClosed(nil, 3*c.rttStats.PTO(false)) return } if closeErr.immediate { - s.connIDGenerator.RemoveAll() + c.connIDGenerator.RemoveAll() return } // Don't send out any CONNECTION_CLOSE if this is an error that occurred // before we even sent out the first packet. - if s.perspective == protocol.PerspectiveClient && !s.sentFirstPacket { - s.connIDGenerator.RemoveAll() + if c.perspective == protocol.PerspectiveClient && !c.sentFirstPacket { + c.connIDGenerator.RemoveAll() return } - connClosePacket, err := s.sendConnectionClose(e) + connClosePacket, err := c.sendConnectionClose(e) if err != nil { - s.logger.Debugf("Error sending CONNECTION_CLOSE: %s", err) + c.logger.Debugf("Error sending CONNECTION_CLOSE: %s", err) } - s.connIDGenerator.ReplaceWithClosed(connClosePacket, 3*s.rttStats.PTO(false)) + c.connIDGenerator.ReplaceWithClosed(connClosePacket, 3*c.rttStats.PTO(false)) } -func (s *connection) dropEncryptionLevel(encLevel protocol.EncryptionLevel, now time.Time) error { - if s.tracer != nil && s.tracer.DroppedEncryptionLevel != nil { - s.tracer.DroppedEncryptionLevel(encLevel) +func (c *Conn) dropEncryptionLevel(encLevel protocol.EncryptionLevel, now time.Time) error { + if c.tracer != nil && c.tracer.DroppedEncryptionLevel != nil { + c.tracer.DroppedEncryptionLevel(encLevel) } - s.sentPacketHandler.DropPackets(encLevel, now) - s.receivedPacketHandler.DropPackets(encLevel) + c.sentPacketHandler.DropPackets(encLevel, now) + c.receivedPacketHandler.DropPackets(encLevel) //nolint:exhaustive // only Initial and 0-RTT need special treatment switch encLevel { case protocol.EncryptionInitial: - s.droppedInitialKeys = true - s.cryptoStreamHandler.DiscardInitialKeys() + c.droppedInitialKeys = true + c.cryptoStreamHandler.DiscardInitialKeys() case protocol.Encryption0RTT: - s.streamsMap.ResetFor0RTT() - s.framer.Handle0RTTRejection() - return s.connFlowController.Reset() + c.streamsMap.ResetFor0RTT() + c.framer.Handle0RTTRejection() + return c.connFlowController.Reset() } - return s.cryptoStreamManager.Drop(encLevel) + return c.cryptoStreamManager.Drop(encLevel) } // is called for the client, when restoring transport parameters saved for 0-RTT -func (s *connection) restoreTransportParameters(params *wire.TransportParameters) { - if s.logger.Debug() { - s.logger.Debugf("Restoring Transport Parameters: %s", params) +func (c *Conn) restoreTransportParameters(params *wire.TransportParameters) { + if c.logger.Debug() { + c.logger.Debugf("Restoring Transport Parameters: %s", params) } - s.peerParams = params - s.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit) - s.connFlowController.UpdateSendWindow(params.InitialMaxData) - s.streamsMap.UpdateLimits(params) - s.connStateMutex.Lock() - s.connState.SupportsDatagrams = s.supportsDatagrams() - s.connStateMutex.Unlock() + c.peerParams = params + c.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit) + c.connFlowController.UpdateSendWindow(params.InitialMaxData) + c.streamsMap.UpdateLimits(params) + c.connStateMutex.Lock() + c.connState.SupportsDatagrams = c.supportsDatagrams() + c.connStateMutex.Unlock() } -func (s *connection) handleTransportParameters(params *wire.TransportParameters) error { - if s.tracer != nil && s.tracer.ReceivedTransportParameters != nil { - s.tracer.ReceivedTransportParameters(params) +func (c *Conn) handleTransportParameters(params *wire.TransportParameters) error { + if c.tracer != nil && c.tracer.ReceivedTransportParameters != nil { + c.tracer.ReceivedTransportParameters(params) } - if err := s.checkTransportParameters(params); err != nil { + if err := c.checkTransportParameters(params); err != nil { return &qerr.TransportError{ ErrorCode: qerr.TransportParameterError, ErrorMessage: err.Error(), } } - if s.perspective == protocol.PerspectiveClient && s.peerParams != nil && s.ConnectionState().Used0RTT && !params.ValidForUpdate(s.peerParams) { + if c.perspective == protocol.PerspectiveClient && c.peerParams != nil && c.ConnectionState().Used0RTT && !params.ValidForUpdate(c.peerParams) { return &qerr.TransportError{ ErrorCode: qerr.ProtocolViolation, ErrorMessage: "server sent reduced limits after accepting 0-RTT data", } } - s.peerParams = params + c.peerParams = params // On the client side we have to wait for handshake completion. // During a 0-RTT connection, we are only allowed to use the new transport parameters for 1-RTT packets. - if s.perspective == protocol.PerspectiveServer { - s.applyTransportParameters() + if c.perspective == protocol.PerspectiveServer { + c.applyTransportParameters() // On the server side, the early connection is ready as soon as we processed // the client's transport parameters. - close(s.earlyConnReadyChan) + close(c.earlyConnReadyChan) } - s.connStateMutex.Lock() - s.connState.SupportsDatagrams = s.supportsDatagrams() - s.connStateMutex.Unlock() + c.connStateMutex.Lock() + c.connState.SupportsDatagrams = c.supportsDatagrams() + c.connStateMutex.Unlock() return nil } -func (s *connection) checkTransportParameters(params *wire.TransportParameters) error { - if s.logger.Debug() { - s.logger.Debugf("Processed Transport Parameters: %s", params) +func (c *Conn) checkTransportParameters(params *wire.TransportParameters) error { + if c.logger.Debug() { + c.logger.Debugf("Processed Transport Parameters: %s", params) } // check the initial_source_connection_id - if params.InitialSourceConnectionID != s.handshakeDestConnID { - return fmt.Errorf("expected initial_source_connection_id to equal %s, is %s", s.handshakeDestConnID, params.InitialSourceConnectionID) + if params.InitialSourceConnectionID != c.handshakeDestConnID { + return fmt.Errorf("expected initial_source_connection_id to equal %s, is %s", c.handshakeDestConnID, params.InitialSourceConnectionID) } - if s.perspective == protocol.PerspectiveServer { + if c.perspective == protocol.PerspectiveServer { return nil } // check the original_destination_connection_id - if params.OriginalDestinationConnectionID != s.origDestConnID { - return fmt.Errorf("expected original_destination_connection_id to equal %s, is %s", s.origDestConnID, params.OriginalDestinationConnectionID) + if params.OriginalDestinationConnectionID != c.origDestConnID { + return fmt.Errorf("expected original_destination_connection_id to equal %s, is %s", c.origDestConnID, params.OriginalDestinationConnectionID) } - if s.retrySrcConnID != nil { // a Retry was performed + if c.retrySrcConnID != nil { // a Retry was performed if params.RetrySourceConnectionID == nil { return errors.New("missing retry_source_connection_id") } - if *params.RetrySourceConnectionID != *s.retrySrcConnID { - return fmt.Errorf("expected retry_source_connection_id to equal %s, is %s", s.retrySrcConnID, *params.RetrySourceConnectionID) + if *params.RetrySourceConnectionID != *c.retrySrcConnID { + return fmt.Errorf("expected retry_source_connection_id to equal %s, is %s", c.retrySrcConnID, *params.RetrySourceConnectionID) } } else if params.RetrySourceConnectionID != nil { return errors.New("received retry_source_connection_id, although no Retry was performed") @@ -2022,56 +1952,55 @@ func (s *connection) checkTransportParameters(params *wire.TransportParameters) return nil } -func (s *connection) applyTransportParameters() { - params := s.peerParams +func (c *Conn) applyTransportParameters() { + params := c.peerParams // Our local idle timeout will always be > 0. - s.idleTimeout = s.config.MaxIdleTimeout + c.idleTimeout = c.config.MaxIdleTimeout // If the peer advertised an idle timeout, take the minimum of the values. if params.MaxIdleTimeout > 0 { - s.idleTimeout = min(s.idleTimeout, params.MaxIdleTimeout) - } - s.keepAliveInterval = min(s.config.KeepAlivePeriod, s.idleTimeout/2) - s.streamsMap.UpdateLimits(params) - s.frameParser.SetAckDelayExponent(params.AckDelayExponent) - s.connFlowController.UpdateSendWindow(params.InitialMaxData) - s.rttStats.SetMaxAckDelay(params.MaxAckDelay) - s.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit) + c.idleTimeout = min(c.idleTimeout, params.MaxIdleTimeout) + } + c.keepAliveInterval = min(c.config.KeepAlivePeriod, c.idleTimeout/2) + c.streamsMap.UpdateLimits(params) + c.frameParser.SetAckDelayExponent(params.AckDelayExponent) + c.connFlowController.UpdateSendWindow(params.InitialMaxData) + c.rttStats.SetMaxAckDelay(params.MaxAckDelay) + c.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit) if params.StatelessResetToken != nil { - s.connIDManager.SetStatelessResetToken(*params.StatelessResetToken) + c.connIDManager.SetStatelessResetToken(*params.StatelessResetToken) } // We don't support connection migration yet, so we don't have any use for the preferred_address. if params.PreferredAddress != nil { // Retire the connection ID. - s.connIDManager.AddFromPreferredAddress(params.PreferredAddress.ConnectionID, params.PreferredAddress.StatelessResetToken) + c.connIDManager.AddFromPreferredAddress(params.PreferredAddress.ConnectionID, params.PreferredAddress.StatelessResetToken) } maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) if params.MaxUDPPayloadSize > 0 && params.MaxUDPPayloadSize < maxPacketSize { maxPacketSize = params.MaxUDPPayloadSize } - s.mtuDiscoverer = newMTUDiscoverer( - s.rttStats, - protocol.ByteCount(s.config.InitialPacketSize), + c.mtuDiscoverer = newMTUDiscoverer( + c.rttStats, + protocol.ByteCount(c.config.InitialPacketSize), maxPacketSize, - s.tracer, + c.tracer, ) } -func (s *connection) triggerSending(now time.Time) error { - s.pacingDeadline = time.Time{} +func (c *Conn) triggerSending(now time.Time) error { + c.pacingDeadline = time.Time{} - sendMode := s.sentPacketHandler.SendMode(now) - //nolint:exhaustive // No need to handle pacing limited here. + sendMode := c.sentPacketHandler.SendMode(now) switch sendMode { case ackhandler.SendAny: - return s.sendPackets(now) + return c.sendPackets(now) case ackhandler.SendNone: return nil case ackhandler.SendPacingLimited: - deadline := s.sentPacketHandler.TimeUntilSend() + deadline := c.sentPacketHandler.TimeUntilSend() if deadline.IsZero() { deadline = deadlineSendImmediately } - s.pacingDeadline = deadline + c.pacingDeadline = deadline // Allow sending of an ACK if we're pacing limit. // This makes sure that a peer that is mostly receiving data (and thus has an inaccurate cwnd estimate) // sends enough ACKs to allow its peer to utilize the bandwidth. @@ -2080,36 +2009,36 @@ func (s *connection) triggerSending(now time.Time) error { // We can at most send a single ACK only packet. // There will only be a new ACK after receiving new packets. // SendAck is only returned when we're congestion limited, so we don't need to set the pacing timer. - return s.maybeSendAckOnlyPacket(now) + return c.maybeSendAckOnlyPacket(now) case ackhandler.SendPTOInitial, ackhandler.SendPTOHandshake, ackhandler.SendPTOAppData: - if err := s.sendProbePacket(sendMode, now); err != nil { + if err := c.sendProbePacket(sendMode, now); err != nil { return err } - if s.sendQueue.WouldBlock() { - s.scheduleSending() + if c.sendQueue.WouldBlock() { + c.scheduleSending() return nil } - return s.triggerSending(now) + return c.triggerSending(now) default: return fmt.Errorf("BUG: invalid send mode %d", sendMode) } } -func (s *connection) sendPackets(now time.Time) error { - if s.perspective == protocol.PerspectiveClient && s.handshakeConfirmed { - if pm := s.pathManagerOutgoing.Load(); pm != nil { +func (c *Conn) sendPackets(now time.Time) error { + if c.perspective == protocol.PerspectiveClient && c.handshakeConfirmed { + if pm := c.pathManagerOutgoing.Load(); pm != nil { connID, frame, tr, ok := pm.NextPathToProbe() if ok { - probe, buf, err := s.packer.PackPathProbePacket(connID, []ackhandler.Frame{frame}, s.version) + probe, buf, err := c.packer.PackPathProbePacket(connID, []ackhandler.Frame{frame}, c.version) if err != nil { return err } - s.logger.Debugf("sending path probe packet from %s", s.LocalAddr()) - s.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) - s.registerPackedShortHeaderPacket(probe, protocol.ECNNon, now) - tr.WriteTo(buf.Data, s.conn.RemoteAddr()) + c.logger.Debugf("sending path probe packet from %s", c.LocalAddr()) + c.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) + c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, now) + tr.WriteTo(buf.Data, c.conn.RemoteAddr()) // There's (likely) more data to send. Loop around again. - s.scheduleSending() + c.scheduleSending() return nil } } @@ -2119,58 +2048,58 @@ func (s *connection) sendPackets(now time.Time) error { // Can't use GSO, since we need to send a single packet that's larger than our current maximum size. // Performance-wise, this doesn't matter, since we only send a very small (<10) number of // MTU probe packets per connection. - if s.handshakeConfirmed && s.mtuDiscoverer != nil && s.mtuDiscoverer.ShouldSendProbe(now) { - ping, size := s.mtuDiscoverer.GetPing(now) - p, buf, err := s.packer.PackMTUProbePacket(ping, size, s.version) + if c.handshakeConfirmed && c.mtuDiscoverer != nil && c.mtuDiscoverer.ShouldSendProbe(now) { + ping, size := c.mtuDiscoverer.GetPing(now) + p, buf, err := c.packer.PackMTUProbePacket(ping, size, c.version) if err != nil { return err } - ecn := s.sentPacketHandler.ECNMode(true) - s.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false) - s.registerPackedShortHeaderPacket(p, ecn, now) - s.sendQueue.Send(buf, 0, ecn) + ecn := c.sentPacketHandler.ECNMode(true) + c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false) + c.registerPackedShortHeaderPacket(p, ecn, now) + c.sendQueue.Send(buf, 0, ecn) // There's (likely) more data to send. Loop around again. - s.scheduleSending() + c.scheduleSending() return nil } - if offset := s.connFlowController.GetWindowUpdate(now); offset > 0 { - s.framer.QueueControlFrame(&wire.MaxDataFrame{MaximumData: offset}) + if offset := c.connFlowController.GetWindowUpdate(now); offset > 0 { + c.framer.QueueControlFrame(&wire.MaxDataFrame{MaximumData: offset}) } - if cf := s.cryptoStreamManager.GetPostHandshakeData(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil { - s.queueControlFrame(cf) + if cf := c.cryptoStreamManager.GetPostHandshakeData(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil { + c.queueControlFrame(cf) } - if !s.handshakeConfirmed { - packet, err := s.packer.PackCoalescedPacket(false, s.maxPacketSize(), now, s.version) + if !c.handshakeConfirmed { + packet, err := c.packer.PackCoalescedPacket(false, c.maxPacketSize(), now, c.version) if err != nil || packet == nil { return err } - s.sentFirstPacket = true - if err := s.sendPackedCoalescedPacket(packet, s.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now); err != nil { + c.sentFirstPacket = true + if err := c.sendPackedCoalescedPacket(packet, c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now); err != nil { return err } //nolint:exhaustive // only need to handle pacing-related events here - switch s.sentPacketHandler.SendMode(now) { + switch c.sentPacketHandler.SendMode(now) { case ackhandler.SendPacingLimited: - s.resetPacingDeadline() + c.resetPacingDeadline() case ackhandler.SendAny: - s.pacingDeadline = deadlineSendImmediately + c.pacingDeadline = deadlineSendImmediately } return nil } - if s.conn.capabilities().GSO { - return s.sendPacketsWithGSO(now) + if c.conn.capabilities().GSO { + return c.sendPacketsWithGSO(now) } - return s.sendPacketsWithoutGSO(now) + return c.sendPacketsWithoutGSO(now) } -func (s *connection) sendPacketsWithoutGSO(now time.Time) error { +func (c *Conn) sendPacketsWithoutGSO(now time.Time) error { for { buf := getPacketBuffer() - ecn := s.sentPacketHandler.ECNMode(true) - if _, err := s.appendOneShortHeaderPacket(buf, s.maxPacketSize(), ecn, now); err != nil { + ecn := c.sentPacketHandler.ECNMode(true) + if _, err := c.appendOneShortHeaderPacket(buf, c.maxPacketSize(), ecn, now); err != nil { if err == errNothingToPack { buf.Release() return nil @@ -2178,38 +2107,38 @@ func (s *connection) sendPacketsWithoutGSO(now time.Time) error { return err } - s.sendQueue.Send(buf, 0, ecn) + c.sendQueue.Send(buf, 0, ecn) - if s.sendQueue.WouldBlock() { + if c.sendQueue.WouldBlock() { return nil } - sendMode := s.sentPacketHandler.SendMode(now) + sendMode := c.sentPacketHandler.SendMode(now) if sendMode == ackhandler.SendPacingLimited { - s.resetPacingDeadline() + c.resetPacingDeadline() return nil } if sendMode != ackhandler.SendAny { return nil } // Prioritize receiving of packets over sending out more packets. - s.receivedPacketMx.Lock() - hasPackets := !s.receivedPackets.Empty() - s.receivedPacketMx.Unlock() + c.receivedPacketMx.Lock() + hasPackets := !c.receivedPackets.Empty() + c.receivedPacketMx.Unlock() if hasPackets { - s.pacingDeadline = deadlineSendImmediately + c.pacingDeadline = deadlineSendImmediately return nil } } } -func (s *connection) sendPacketsWithGSO(now time.Time) error { +func (c *Conn) sendPacketsWithGSO(now time.Time) error { buf := getLargePacketBuffer() - maxSize := s.maxPacketSize() + maxSize := c.maxPacketSize() - ecn := s.sentPacketHandler.ECNMode(true) + ecn := c.sentPacketHandler.ECNMode(true) for { var dontSendMore bool - size, err := s.appendOneShortHeaderPacket(buf, maxSize, ecn, now) + size, err := c.appendOneShortHeaderPacket(buf, maxSize, ecn, now) if err != nil { if err != errNothingToPack { return err @@ -2222,9 +2151,9 @@ func (s *connection) sendPacketsWithGSO(now time.Time) error { } if !dontSendMore { - sendMode := s.sentPacketHandler.SendMode(now) + sendMode := c.sentPacketHandler.SendMode(now) if sendMode == ackhandler.SendPacingLimited { - s.resetPacingDeadline() + c.resetPacingDeadline() } if sendMode != ackhandler.SendAny { dontSendMore = true @@ -2232,7 +2161,7 @@ func (s *connection) sendPacketsWithGSO(now time.Time) error { } // Don't send more packets in this batch if they require a different ECN marking than the previous ones. - nextECN := s.sentPacketHandler.ECNMode(true) + nextECN := c.sentPacketHandler.ECNMode(true) // Append another packet if // 1. The congestion controller and pacer allow sending more @@ -2243,21 +2172,21 @@ func (s *connection) sendPacketsWithGSO(now time.Time) error { continue } - s.sendQueue.Send(buf, uint16(maxSize), ecn) + c.sendQueue.Send(buf, uint16(maxSize), ecn) if dontSendMore { return nil } - if s.sendQueue.WouldBlock() { + if c.sendQueue.WouldBlock() { return nil } // Prioritize receiving of packets over sending out more packets. - s.receivedPacketMx.Lock() - hasPackets := !s.receivedPackets.Empty() - s.receivedPacketMx.Unlock() + c.receivedPacketMx.Lock() + hasPackets := !c.receivedPackets.Empty() + c.receivedPacketMx.Unlock() if hasPackets { - s.pacingDeadline = deadlineSendImmediately + c.pacingDeadline = deadlineSendImmediately return nil } @@ -2266,42 +2195,42 @@ func (s *connection) sendPacketsWithGSO(now time.Time) error { } } -func (s *connection) resetPacingDeadline() { - deadline := s.sentPacketHandler.TimeUntilSend() +func (c *Conn) resetPacingDeadline() { + deadline := c.sentPacketHandler.TimeUntilSend() if deadline.IsZero() { deadline = deadlineSendImmediately } - s.pacingDeadline = deadline + c.pacingDeadline = deadline } -func (s *connection) maybeSendAckOnlyPacket(now time.Time) error { - if !s.handshakeConfirmed { - ecn := s.sentPacketHandler.ECNMode(false) - packet, err := s.packer.PackCoalescedPacket(true, s.maxPacketSize(), now, s.version) +func (c *Conn) maybeSendAckOnlyPacket(now time.Time) error { + if !c.handshakeConfirmed { + ecn := c.sentPacketHandler.ECNMode(false) + packet, err := c.packer.PackCoalescedPacket(true, c.maxPacketSize(), now, c.version) if err != nil { return err } if packet == nil { return nil } - return s.sendPackedCoalescedPacket(packet, ecn, now) + return c.sendPackedCoalescedPacket(packet, ecn, now) } - ecn := s.sentPacketHandler.ECNMode(true) - p, buf, err := s.packer.PackAckOnlyPacket(s.maxPacketSize(), now, s.version) + ecn := c.sentPacketHandler.ECNMode(true) + p, buf, err := c.packer.PackAckOnlyPacket(c.maxPacketSize(), now, c.version) if err != nil { if err == errNothingToPack { return nil } return err } - s.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false) - s.registerPackedShortHeaderPacket(p, ecn, now) - s.sendQueue.Send(buf, 0, ecn) + c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false) + c.registerPackedShortHeaderPacket(p, ecn, now) + c.sendQueue.Send(buf, 0, ecn) return nil } -func (s *connection) sendProbePacket(sendMode ackhandler.SendMode, now time.Time) error { +func (c *Conn) sendProbePacket(sendMode ackhandler.SendMode, now time.Time) error { var encLevel protocol.EncryptionLevel //nolint:exhaustive // We only need to handle the PTO send modes here. switch sendMode { @@ -2318,18 +2247,18 @@ func (s *connection) sendProbePacket(sendMode ackhandler.SendMode, now time.Time // or until there are no more packets to queue. var packet *coalescedPacket for packet == nil { - if wasQueued := s.sentPacketHandler.QueueProbePacket(encLevel); !wasQueued { + if wasQueued := c.sentPacketHandler.QueueProbePacket(encLevel); !wasQueued { break } var err error - packet, err = s.packer.PackPTOProbePacket(encLevel, s.maxPacketSize(), false, now, s.version) + packet, err = c.packer.PackPTOProbePacket(encLevel, c.maxPacketSize(), false, now, c.version) if err != nil { return err } } if packet == nil { var err error - packet, err = s.packer.PackPTOProbePacket(encLevel, s.maxPacketSize(), true, now, s.version) + packet, err = c.packer.PackPTOProbePacket(encLevel, c.maxPacketSize(), true, now, c.version) if err != nil { return err } @@ -2337,26 +2266,26 @@ func (s *connection) sendProbePacket(sendMode ackhandler.SendMode, now time.Time if packet == nil || (len(packet.longHdrPackets) == 0 && packet.shortHdrPacket == nil) { return fmt.Errorf("connection BUG: couldn't pack %s probe packet: %v", encLevel, packet) } - return s.sendPackedCoalescedPacket(packet, s.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now) + return c.sendPackedCoalescedPacket(packet, c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now) } // appendOneShortHeaderPacket appends a new packet to the given packetBuffer. // If there was nothing to pack, the returned size is 0. -func (s *connection) appendOneShortHeaderPacket(buf *packetBuffer, maxSize protocol.ByteCount, ecn protocol.ECN, now time.Time) (protocol.ByteCount, error) { +func (c *Conn) appendOneShortHeaderPacket(buf *packetBuffer, maxSize protocol.ByteCount, ecn protocol.ECN, now time.Time) (protocol.ByteCount, error) { startLen := buf.Len() - p, err := s.packer.AppendPacket(buf, maxSize, now, s.version) + p, err := c.packer.AppendPacket(buf, maxSize, now, c.version) if err != nil { return 0, err } size := buf.Len() - startLen - s.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, size, false) - s.registerPackedShortHeaderPacket(p, ecn, now) + c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, size, false) + c.registerPackedShortHeaderPacket(p, ecn, now) return size, nil } -func (s *connection) registerPackedShortHeaderPacket(p shortHeaderPacket, ecn protocol.ECN, now time.Time) { +func (c *Conn) registerPackedShortHeaderPacket(p shortHeaderPacket, ecn protocol.ECN, now time.Time) { if p.IsPathProbePacket { - s.sentPacketHandler.SentPacket( + c.sentPacketHandler.SentPacket( now, p.PacketNumber, protocol.InvalidPacketNumber, @@ -2370,15 +2299,15 @@ func (s *connection) registerPackedShortHeaderPacket(p shortHeaderPacket, ecn pr ) return } - if s.firstAckElicitingPacketAfterIdleSentTime.IsZero() && (len(p.StreamFrames) > 0 || ackhandler.HasAckElicitingFrames(p.Frames)) { - s.firstAckElicitingPacketAfterIdleSentTime = now + if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && (len(p.StreamFrames) > 0 || ackhandler.HasAckElicitingFrames(p.Frames)) { + c.firstAckElicitingPacketAfterIdleSentTime = now } largestAcked := protocol.InvalidPacketNumber if p.Ack != nil { largestAcked = p.Ack.LargestAcked() } - s.sentPacketHandler.SentPacket( + c.sentPacketHandler.SentPacket( now, p.PacketNumber, largestAcked, @@ -2390,20 +2319,20 @@ func (s *connection) registerPackedShortHeaderPacket(p shortHeaderPacket, ecn pr p.IsPathMTUProbePacket, false, ) - s.connIDManager.SentPacket() + c.connIDManager.SentPacket() } -func (s *connection) sendPackedCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN, now time.Time) error { - s.logCoalescedPacket(packet, ecn) +func (c *Conn) sendPackedCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN, now time.Time) error { + c.logCoalescedPacket(packet, ecn) for _, p := range packet.longHdrPackets { - if s.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() { - s.firstAckElicitingPacketAfterIdleSentTime = now + if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() { + c.firstAckElicitingPacketAfterIdleSentTime = now } largestAcked := protocol.InvalidPacketNumber if p.ack != nil { largestAcked = p.ack.LargestAcked() } - s.sentPacketHandler.SentPacket( + c.sentPacketHandler.SentPacket( now, p.header.PacketNumber, largestAcked, @@ -2415,24 +2344,24 @@ func (s *connection) sendPackedCoalescedPacket(packet *coalescedPacket, ecn prot false, false, ) - if s.perspective == protocol.PerspectiveClient && p.EncryptionLevel() == protocol.EncryptionHandshake && - !s.droppedInitialKeys { + if c.perspective == protocol.PerspectiveClient && p.EncryptionLevel() == protocol.EncryptionHandshake && + !c.droppedInitialKeys { // On the client side, Initial keys are dropped as soon as the first Handshake packet is sent. // See Section 4.9.1 of RFC 9001. - if err := s.dropEncryptionLevel(protocol.EncryptionInitial, now); err != nil { + if err := c.dropEncryptionLevel(protocol.EncryptionInitial, now); err != nil { return err } } } if p := packet.shortHdrPacket; p != nil { - if s.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() { - s.firstAckElicitingPacketAfterIdleSentTime = now + if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() { + c.firstAckElicitingPacketAfterIdleSentTime = now } largestAcked := protocol.InvalidPacketNumber if p.Ack != nil { largestAcked = p.Ack.LargestAcked() } - s.sentPacketHandler.SentPacket( + c.sentPacketHandler.SentPacket( now, p.PacketNumber, largestAcked, @@ -2445,41 +2374,41 @@ func (s *connection) sendPackedCoalescedPacket(packet *coalescedPacket, ecn prot false, ) } - s.connIDManager.SentPacket() - s.sendQueue.Send(packet.buffer, 0, ecn) + c.connIDManager.SentPacket() + c.sendQueue.Send(packet.buffer, 0, ecn) return nil } -func (s *connection) sendConnectionClose(e error) ([]byte, error) { +func (c *Conn) sendConnectionClose(e error) ([]byte, error) { var packet *coalescedPacket var err error var transportErr *qerr.TransportError var applicationErr *qerr.ApplicationError if errors.As(e, &transportErr) { - packet, err = s.packer.PackConnectionClose(transportErr, s.maxPacketSize(), s.version) + packet, err = c.packer.PackConnectionClose(transportErr, c.maxPacketSize(), c.version) } else if errors.As(e, &applicationErr) { - packet, err = s.packer.PackApplicationClose(applicationErr, s.maxPacketSize(), s.version) + packet, err = c.packer.PackApplicationClose(applicationErr, c.maxPacketSize(), c.version) } else { - packet, err = s.packer.PackConnectionClose(&qerr.TransportError{ + packet, err = c.packer.PackConnectionClose(&qerr.TransportError{ ErrorCode: qerr.InternalError, ErrorMessage: fmt.Sprintf("connection BUG: unspecified error type (msg: %s)", e.Error()), - }, s.maxPacketSize(), s.version) + }, c.maxPacketSize(), c.version) } if err != nil { return nil, err } - ecn := s.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()) - s.logCoalescedPacket(packet, ecn) - return packet.buffer.Data, s.conn.Write(packet.buffer.Data, 0, ecn) + ecn := c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()) + c.logCoalescedPacket(packet, ecn) + return packet.buffer.Data, c.conn.Write(packet.buffer.Data, 0, ecn) } -func (s *connection) maxPacketSize() protocol.ByteCount { - if s.mtuDiscoverer == nil { +func (c *Conn) maxPacketSize() protocol.ByteCount { + if c.mtuDiscoverer == nil { // Use the configured packet size on the client side. // If the server sends a max_udp_payload_size that's smaller than this size, we can ignore this: // Apparently the server still processed the (fully padded) Initial packet anyway. - if s.perspective == protocol.PerspectiveClient { - return protocol.ByteCount(s.config.InitialPacketSize) + if c.perspective == protocol.PerspectiveClient { + return protocol.ByteCount(c.config.InitialPacketSize) } // On the server side, there's no downside to using 1200 bytes until we received the client's transport // parameters: @@ -2488,109 +2417,137 @@ func (s *connection) maxPacketSize() protocol.ByteCount { // * If it did, we will have processed the transport parameters and initialized the MTU discoverer. return protocol.MinInitialPacketSize } - return s.mtuDiscoverer.CurrentSize() + return c.mtuDiscoverer.CurrentSize() } -// AcceptStream returns the next stream openend by the peer -func (s *connection) AcceptStream(ctx context.Context) (Stream, error) { - return s.streamsMap.AcceptStream(ctx) +// AcceptStream returns the next stream opened by the peer, blocking until one is available. +func (c *Conn) AcceptStream(ctx context.Context) (*Stream, error) { + return c.streamsMap.AcceptStream(ctx) } -func (s *connection) AcceptUniStream(ctx context.Context) (ReceiveStream, error) { - return s.streamsMap.AcceptUniStream(ctx) +// AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. +func (c *Conn) AcceptUniStream(ctx context.Context) (*ReceiveStream, error) { + return c.streamsMap.AcceptUniStream(ctx) } -// OpenStream opens a stream -func (s *connection) OpenStream() (Stream, error) { - return s.streamsMap.OpenStream() +// OpenStream opens a new bidirectional QUIC stream. +// There is no signaling to the peer about new streams: +// The peer can only accept the stream after data has been sent on the stream, +// or the stream has been reset or closed. +// When reaching the peer's stream limit, it is not possible to open a new stream until the +// peer raises the stream limit. In that case, a [StreamLimitReachedError] is returned. +func (c *Conn) OpenStream() (*Stream, error) { + return c.streamsMap.OpenStream() } -func (s *connection) OpenStreamSync(ctx context.Context) (Stream, error) { - return s.streamsMap.OpenStreamSync(ctx) +// OpenStreamSync opens a new bidirectional QUIC stream. +// It blocks until a new stream can be opened. +// There is no signaling to the peer about new streams: +// The peer can only accept the stream after data has been sent on the stream, +// or the stream has been reset or closed. +func (c *Conn) OpenStreamSync(ctx context.Context) (*Stream, error) { + return c.streamsMap.OpenStreamSync(ctx) } -func (s *connection) OpenUniStream() (SendStream, error) { - return s.streamsMap.OpenUniStream() +// OpenUniStream opens a new outgoing unidirectional QUIC stream. +// There is no signaling to the peer about new streams: +// The peer can only accept the stream after data has been sent on the stream, +// or the stream has been reset or closed. +// When reaching the peer's stream limit, it is not possible to open a new stream until the +// peer raises the stream limit. In that case, a [StreamLimitReachedError] is returned. +func (c *Conn) OpenUniStream() (*SendStream, error) { + return c.streamsMap.OpenUniStream() } -func (s *connection) OpenUniStreamSync(ctx context.Context) (SendStream, error) { - return s.streamsMap.OpenUniStreamSync(ctx) +// OpenUniStreamSync opens a new outgoing unidirectional QUIC stream. +// It blocks until a new stream can be opened. +// There is no signaling to the peer about new streams: +// The peer can only accept the stream after data has been sent on the stream, +// or the stream has been reset or closed. +func (c *Conn) OpenUniStreamSync(ctx context.Context) (*SendStream, error) { + return c.streamsMap.OpenUniStreamSync(ctx) } -func (s *connection) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController { - initialSendWindow := s.peerParams.InitialMaxStreamDataUni +func (c *Conn) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController { + initialSendWindow := c.peerParams.InitialMaxStreamDataUni if id.Type() == protocol.StreamTypeBidi { - if id.InitiatedBy() == s.perspective { - initialSendWindow = s.peerParams.InitialMaxStreamDataBidiRemote + if id.InitiatedBy() == c.perspective { + initialSendWindow = c.peerParams.InitialMaxStreamDataBidiRemote } else { - initialSendWindow = s.peerParams.InitialMaxStreamDataBidiLocal + initialSendWindow = c.peerParams.InitialMaxStreamDataBidiLocal } } return flowcontrol.NewStreamFlowController( id, - s.connFlowController, - protocol.ByteCount(s.config.InitialStreamReceiveWindow), - protocol.ByteCount(s.config.MaxStreamReceiveWindow), + c.connFlowController, + protocol.ByteCount(c.config.InitialStreamReceiveWindow), + protocol.ByteCount(c.config.MaxStreamReceiveWindow), initialSendWindow, - s.rttStats, - s.logger, + c.rttStats, + c.logger, ) } // scheduleSending signals that we have data for sending -func (s *connection) scheduleSending() { +func (c *Conn) scheduleSending() { select { - case s.sendingScheduled <- struct{}{}: + case c.sendingScheduled <- struct{}{}: default: } } // tryQueueingUndecryptablePacket queues a packet for which we're missing the decryption keys. // The logging.PacketType is only used for logging purposes. -func (s *connection) tryQueueingUndecryptablePacket(p receivedPacket, pt logging.PacketType) { - if s.handshakeComplete { +func (c *Conn) tryQueueingUndecryptablePacket(p receivedPacket, pt logging.PacketType) { + if c.handshakeComplete { panic("shouldn't queue undecryptable packets after handshake completion") } - if len(s.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets { - if s.tracer != nil && s.tracer.DroppedPacket != nil { - s.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention) + if len(c.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets { + if c.tracer != nil && c.tracer.DroppedPacket != nil { + c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention) } - s.logger.Infof("Dropping undecryptable packet (%d bytes). Undecryptable packet queue full.", p.Size()) + c.logger.Infof("Dropping undecryptable packet (%d bytes). Undecryptable packet queue full.", p.Size()) return } - s.logger.Infof("Queueing packet (%d bytes) for later decryption", p.Size()) - if s.tracer != nil && s.tracer.BufferedPacket != nil { - s.tracer.BufferedPacket(pt, p.Size()) + c.logger.Infof("Queueing packet (%d bytes) for later decryption", p.Size()) + if c.tracer != nil && c.tracer.BufferedPacket != nil { + c.tracer.BufferedPacket(pt, p.Size()) } - s.undecryptablePackets = append(s.undecryptablePackets, p) + c.undecryptablePackets = append(c.undecryptablePackets, p) } -func (s *connection) queueControlFrame(f wire.Frame) { - s.framer.QueueControlFrame(f) - s.scheduleSending() +func (c *Conn) queueControlFrame(f wire.Frame) { + c.framer.QueueControlFrame(f) + c.scheduleSending() } -func (s *connection) onHasConnectionData() { s.scheduleSending() } +func (c *Conn) onHasConnectionData() { c.scheduleSending() } -func (s *connection) onHasStreamData(id protocol.StreamID, str sendStreamI) { - s.framer.AddActiveStream(id, str) - s.scheduleSending() +func (c *Conn) onHasStreamData(id protocol.StreamID, str *SendStream) { + c.framer.AddActiveStream(id, str) + c.scheduleSending() } -func (s *connection) onHasStreamControlFrame(id protocol.StreamID, str streamControlFrameGetter) { - s.framer.AddStreamWithControlFrames(id, str) - s.scheduleSending() +func (c *Conn) onHasStreamControlFrame(id protocol.StreamID, str streamControlFrameGetter) { + c.framer.AddStreamWithControlFrames(id, str) + c.scheduleSending() } -func (s *connection) onStreamCompleted(id protocol.StreamID) { - if err := s.streamsMap.DeleteStream(id); err != nil { - s.closeLocal(err) +func (c *Conn) onStreamCompleted(id protocol.StreamID) { + if err := c.streamsMap.DeleteStream(id); err != nil { + c.closeLocal(err) } - s.framer.RemoveActiveStream(id) + c.framer.RemoveActiveStream(id) } -func (s *connection) SendDatagram(p []byte) error { - if !s.supportsDatagrams() { +// SendDatagram sends a message using a QUIC datagram, as specified in RFC 9221, +// if the peer enabled datagram support. +// There is no delivery guarantee for DATAGRAM frames, they are not retransmitted if lost. +// The payload of the datagram needs to fit into a single QUIC packet. +// In addition, a datagram may be dropped before being sent out if the available packet size suddenly decreases. +// If the payload is too large to be sent at the current time, a DatagramTooLargeError is returned. +func (c *Conn) SendDatagram(p []byte) error { + if !c.supportsDatagrams() { return errors.New("datagram support disabled") } @@ -2598,59 +2555,63 @@ func (s *connection) SendDatagram(p []byte) error { // The payload size estimate is conservative. // Under many circumstances we could send a few more bytes. maxDataLen := min( - f.MaxDataLen(s.peerParams.MaxDatagramFrameSize, s.version), - protocol.ByteCount(s.currentMTUEstimate.Load()), + f.MaxDataLen(c.peerParams.MaxDatagramFrameSize, c.version), + protocol.ByteCount(c.currentMTUEstimate.Load()), ) if protocol.ByteCount(len(p)) > maxDataLen { return &DatagramTooLargeError{MaxDatagramPayloadSize: int64(maxDataLen)} } f.Data = make([]byte, len(p)) copy(f.Data, p) - return s.datagramQueue.Add(f) + return c.datagramQueue.Add(f) } -func (s *connection) ReceiveDatagram(ctx context.Context) ([]byte, error) { - if !s.config.EnableDatagrams { +// ReceiveDatagram gets a message received in a QUIC datagram, as specified in RFC 9221. +func (c *Conn) ReceiveDatagram(ctx context.Context) ([]byte, error) { + if !c.config.EnableDatagrams { return nil, errors.New("datagram support disabled") } - return s.datagramQueue.Receive(ctx) + return c.datagramQueue.Receive(ctx) } -func (s *connection) LocalAddr() net.Addr { return s.conn.LocalAddr() } -func (s *connection) RemoteAddr() net.Addr { return s.conn.RemoteAddr() } +// LocalAddr returns the local address of the QUIC connection. +func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() } -func (s *connection) getPathManager() *pathManagerOutgoing { - s.pathManagerOutgoing.CompareAndSwap(nil, +// RemoteAddr returns the remote address of the QUIC connection. +func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } + +func (c *Conn) getPathManager() *pathManagerOutgoing { + c.pathManagerOutgoing.CompareAndSwap(nil, func() *pathManagerOutgoing { // this function is only called if a swap is performed return newPathManagerOutgoing( - s.connIDManager.GetConnIDForPath, - s.connIDManager.RetireConnIDForPath, - s.scheduleSending, + c.connIDManager.GetConnIDForPath, + c.connIDManager.RetireConnIDForPath, + c.scheduleSending, ) }(), ) - return s.pathManagerOutgoing.Load() + return c.pathManagerOutgoing.Load() } -func (s *connection) AddPath(t *Transport) (*Path, error) { - if s.perspective == protocol.PerspectiveServer { +func (c *Conn) AddPath(t *Transport) (*Path, error) { + if c.perspective == protocol.PerspectiveServer { return nil, errors.New("server cannot initiate connection migration") } - if s.peerParams.DisableActiveMigration { + if c.peerParams.DisableActiveMigration { return nil, errors.New("server disabled connection migration") } if err := t.init(false); err != nil { return nil, err } - return s.getPathManager().NewPath( + return c.getPathManager().NewPath( t, 200*time.Millisecond, // initial RTT estimate func() { runner := (*packetHandlerMap)(t) - s.connIDGenerator.AddConnRunner( + c.connIDGenerator.AddConnRunner( runner, connRunnerCallbacks{ - AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) }, + AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, c) }, RemoveConnectionID: runner.Remove, ReplaceWithClosed: runner.ReplaceWithClosed, }, @@ -2659,17 +2620,25 @@ func (s *connection) AddPath(t *Transport) (*Path, error) { ), nil } -func (s *connection) NextConnection(ctx context.Context) (Connection, error) { +// HandshakeComplete blocks until the handshake completes (or fails). +// For the client, data sent before completion of the handshake is encrypted with 0-RTT keys. +// For the server, data sent before completion of the handshake is encrypted with 1-RTT keys, +// however the client's identity is only verified once the handshake completes. +func (c *Conn) HandshakeComplete() <-chan struct{} { + return c.handshakeCompleteChan +} + +func (c *Conn) NextConnection(ctx context.Context) (*Conn, error) { // The handshake might fail after the server rejected 0-RTT. // This could happen if the Finished message is malformed or never received. select { case <-ctx.Done(): return nil, context.Cause(ctx) - case <-s.Context().Done(): - case <-s.HandshakeComplete(): - s.streamsMap.UseResetMaps() + case <-c.Context().Done(): + case <-c.HandshakeComplete(): + c.streamsMap.UseResetMaps() } - return s, nil + return c, nil } // estimateMaxPayloadSize estimates the maximum payload size for short header packets. diff --git a/vendor/github.com/quic-go/quic-go/connection_logging.go b/vendor/github.com/quic-go/quic-go/connection_logging.go index a314a6cd67..5ea12d130c 100644 --- a/vendor/github.com/quic-go/quic-go/connection_logging.go +++ b/vendor/github.com/quic-go/quic-go/connection_logging.go @@ -50,23 +50,23 @@ func toLoggingAckFrame(f *wire.AckFrame) *logging.AckFrame { return ack } -func (s *connection) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN) { +func (c *Conn) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN) { // quic-go logging - if s.logger.Debug() { - p.header.Log(s.logger) + if c.logger.Debug() { + p.header.Log(c.logger) if p.ack != nil { - wire.LogFrame(s.logger, p.ack, true) + wire.LogFrame(c.logger, p.ack, true) } for _, frame := range p.frames { - wire.LogFrame(s.logger, frame.Frame, true) + wire.LogFrame(c.logger, frame.Frame, true) } for _, frame := range p.streamFrames { - wire.LogFrame(s.logger, frame.Frame, true) + wire.LogFrame(c.logger, frame.Frame, true) } } // tracing - if s.tracer != nil && s.tracer.SentLongHeaderPacket != nil { + if c.tracer != nil && c.tracer.SentLongHeaderPacket != nil { frames := make([]logging.Frame, 0, len(p.frames)) for _, f := range p.frames { frames = append(frames, toLoggingFrame(f.Frame)) @@ -78,11 +78,11 @@ func (s *connection) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN) if p.ack != nil { ack = toLoggingAckFrame(p.ack) } - s.tracer.SentLongHeaderPacket(p.header, p.length, ecn, ack, frames) + c.tracer.SentLongHeaderPacket(p.header, p.length, ecn, ack, frames) } } -func (s *connection) logShortHeaderPacket( +func (c *Conn) logShortHeaderPacket( destConnID protocol.ConnectionID, ackFrame *wire.AckFrame, frames []ackhandler.Frame, @@ -94,25 +94,25 @@ func (s *connection) logShortHeaderPacket( size protocol.ByteCount, isCoalesced bool, ) { - if s.logger.Debug() && !isCoalesced { - s.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, 1-RTT (ECN: %s)", pn, size, s.logID, ecn) + if c.logger.Debug() && !isCoalesced { + c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, 1-RTT (ECN: %s)", pn, size, c.logID, ecn) } // quic-go logging - if s.logger.Debug() { - wire.LogShortHeader(s.logger, destConnID, pn, pnLen, kp) + if c.logger.Debug() { + wire.LogShortHeader(c.logger, destConnID, pn, pnLen, kp) if ackFrame != nil { - wire.LogFrame(s.logger, ackFrame, true) + wire.LogFrame(c.logger, ackFrame, true) } for _, f := range frames { - wire.LogFrame(s.logger, f.Frame, true) + wire.LogFrame(c.logger, f.Frame, true) } for _, f := range streamFrames { - wire.LogFrame(s.logger, f.Frame, true) + wire.LogFrame(c.logger, f.Frame, true) } } // tracing - if s.tracer != nil && s.tracer.SentShortHeaderPacket != nil { + if c.tracer != nil && c.tracer.SentShortHeaderPacket != nil { fs := make([]logging.Frame, 0, len(frames)+len(streamFrames)) for _, f := range frames { fs = append(fs, toLoggingFrame(f.Frame)) @@ -124,7 +124,7 @@ func (s *connection) logShortHeaderPacket( if ackFrame != nil { ack = toLoggingAckFrame(ackFrame) } - s.tracer.SentShortHeaderPacket( + c.tracer.SentShortHeaderPacket( &logging.ShortHeader{DestConnectionID: destConnID, PacketNumber: pn, PacketNumberLen: pnLen, KeyPhase: kp}, size, ecn, @@ -134,12 +134,12 @@ func (s *connection) logShortHeaderPacket( } } -func (s *connection) logCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN) { - if s.logger.Debug() { +func (c *Conn) logCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN) { + if c.logger.Debug() { // There's a short period between dropping both Initial and Handshake keys and completion of the handshake, // during which we might call PackCoalescedPacket but just pack a short header packet. if len(packet.longHdrPackets) == 0 && packet.shortHdrPacket != nil { - s.logShortHeaderPacket( + c.logShortHeaderPacket( packet.shortHdrPacket.DestConnID, packet.shortHdrPacket.Ack, packet.shortHdrPacket.Frames, @@ -154,15 +154,15 @@ func (s *connection) logCoalescedPacket(packet *coalescedPacket, ecn protocol.EC return } if len(packet.longHdrPackets) > 1 { - s.logger.Debugf("-> Sending coalesced packet (%d parts, %d bytes) for connection %s", len(packet.longHdrPackets), packet.buffer.Len(), s.logID) + c.logger.Debugf("-> Sending coalesced packet (%d parts, %d bytes) for connection %s", len(packet.longHdrPackets), packet.buffer.Len(), c.logID) } else { - s.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, %s", packet.longHdrPackets[0].header.PacketNumber, packet.buffer.Len(), s.logID, packet.longHdrPackets[0].EncryptionLevel()) + c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, %s", packet.longHdrPackets[0].header.PacketNumber, packet.buffer.Len(), c.logID, packet.longHdrPackets[0].EncryptionLevel()) } } for _, p := range packet.longHdrPackets { - s.logLongHeaderPacket(p, ecn) + c.logLongHeaderPacket(p, ecn) } if p := packet.shortHdrPacket; p != nil { - s.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, p.Length, true) + c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, p.Length, true) } } diff --git a/vendor/github.com/quic-go/quic-go/errors.go b/vendor/github.com/quic-go/quic-go/errors.go index 4a69a7f193..829730fecd 100644 --- a/vendor/github.com/quic-go/quic-go/errors.go +++ b/vendor/github.com/quic-go/quic-go/errors.go @@ -7,42 +7,72 @@ import ( ) type ( - TransportError = qerr.TransportError - ApplicationError = qerr.ApplicationError + // TransportError indicates an error that occurred on the QUIC transport layer. + // Every transport error other than CONNECTION_REFUSED and APPLICATION_ERROR is + // likely a bug in the implementation. + TransportError = qerr.TransportError + // ApplicationError is an application-defined error. + ApplicationError = qerr.ApplicationError + // VersionNegotiationError indicates a failure to negotiate a QUIC version. VersionNegotiationError = qerr.VersionNegotiationError - StatelessResetError = qerr.StatelessResetError - IdleTimeoutError = qerr.IdleTimeoutError - HandshakeTimeoutError = qerr.HandshakeTimeoutError + // StatelessResetError indicates a stateless reset was received. + // This can happen when the peer reboots, or when packets are misrouted. + // See section 10.3 of RFC 9000 for details. + StatelessResetError = qerr.StatelessResetError + // IdleTimeoutError indicates that the connection timed out because it was inactive for too long. + IdleTimeoutError = qerr.IdleTimeoutError + // HandshakeTimeoutError indicates that the connection timed out before completing the handshake. + HandshakeTimeoutError = qerr.HandshakeTimeoutError ) type ( - TransportErrorCode = qerr.TransportErrorCode + // TransportErrorCode is a QUIC transport error code, see section 20 of RFC 9000. + TransportErrorCode = qerr.TransportErrorCode + // ApplicationErrorCode is an QUIC application error code. ApplicationErrorCode = qerr.ApplicationErrorCode - StreamErrorCode = qerr.StreamErrorCode + // StreamErrorCode is a QUIC stream error code. The meaning of the value is defined by the application. + StreamErrorCode = qerr.StreamErrorCode ) const ( - NoError = qerr.NoError - InternalError = qerr.InternalError - ConnectionRefused = qerr.ConnectionRefused - FlowControlError = qerr.FlowControlError - StreamLimitError = qerr.StreamLimitError - StreamStateError = qerr.StreamStateError - FinalSizeError = qerr.FinalSizeError - FrameEncodingError = qerr.FrameEncodingError - TransportParameterError = qerr.TransportParameterError - ConnectionIDLimitError = qerr.ConnectionIDLimitError - ProtocolViolation = qerr.ProtocolViolation - InvalidToken = qerr.InvalidToken + // NoError is the NO_ERROR transport error code. + NoError = qerr.NoError + // InternalError is the INTERNAL_ERROR transport error code. + InternalError = qerr.InternalError + // ConnectionRefused is the CONNECTION_REFUSED transport error code. + ConnectionRefused = qerr.ConnectionRefused + // FlowControlError is the FLOW_CONTROL_ERROR transport error code. + FlowControlError = qerr.FlowControlError + // StreamLimitError is the STREAM_LIMIT_ERROR transport error code. + StreamLimitError = qerr.StreamLimitError + // StreamStateError is the STREAM_STATE_ERROR transport error code. + StreamStateError = qerr.StreamStateError + // FinalSizeError is the FINAL_SIZE_ERROR transport error code. + FinalSizeError = qerr.FinalSizeError + // FrameEncodingError is the FRAME_ENCODING_ERROR transport error code. + FrameEncodingError = qerr.FrameEncodingError + // TransportParameterError is the TRANSPORT_PARAMETER_ERROR transport error code. + TransportParameterError = qerr.TransportParameterError + // ConnectionIDLimitError is the CONNECTION_ID_LIMIT_ERROR transport error code. + ConnectionIDLimitError = qerr.ConnectionIDLimitError + // ProtocolViolation is the PROTOCOL_VIOLATION transport error code. + ProtocolViolation = qerr.ProtocolViolation + // InvalidToken is the INVALID_TOKEN transport error code. + InvalidToken = qerr.InvalidToken + // ApplicationErrorErrorCode is the APPLICATION_ERROR transport error code. ApplicationErrorErrorCode = qerr.ApplicationErrorErrorCode - CryptoBufferExceeded = qerr.CryptoBufferExceeded - KeyUpdateError = qerr.KeyUpdateError - AEADLimitReached = qerr.AEADLimitReached - NoViablePathError = qerr.NoViablePathError + // CryptoBufferExceeded is the CRYPTO_BUFFER_EXCEEDED transport error code. + CryptoBufferExceeded = qerr.CryptoBufferExceeded + // KeyUpdateError is the KEY_UPDATE_ERROR transport error code. + KeyUpdateError = qerr.KeyUpdateError + // AEADLimitReached is the AEAD_LIMIT_REACHED transport error code. + AEADLimitReached = qerr.AEADLimitReached + // NoViablePathError is the NO_VIABLE_PATH_ERROR transport error code. + NoViablePathError = qerr.NoViablePathError ) -// A StreamError is used for Stream.CancelRead and Stream.CancelWrite. -// It is also returned from Stream.Read and Stream.Write if the peer canceled reading or writing. +// A StreamError is used to signal stream cancellations. +// It is returned from the Read and Write methods of the [ReceiveStream], [SendStream] and [Stream]. type StreamError struct { StreamID StreamID ErrorCode StreamErrorCode @@ -62,7 +92,7 @@ func (e *StreamError) Error() string { return fmt.Sprintf("stream %d canceled by %s with error code %d", e.StreamID, pers, e.ErrorCode) } -// DatagramTooLargeError is returned from Connection.SendDatagram if the payload is too large to be sent. +// DatagramTooLargeError is returned from Conn.SendDatagram if the payload is too large to be sent. type DatagramTooLargeError struct { MaxDatagramPayloadSize int64 } diff --git a/vendor/github.com/quic-go/quic-go/framer.go b/vendor/github.com/quic-go/quic-go/framer.go index fee3163155..a331202d02 100644 --- a/vendor/github.com/quic-go/quic-go/framer.go +++ b/vendor/github.com/quic-go/quic-go/framer.go @@ -22,6 +22,10 @@ const ( // (which is the RESET_STREAM frame). const maxStreamControlFrameSize = 25 +type streamFrameGetter interface { + popStreamFrame(protocol.ByteCount, protocol.Version) (ackhandler.StreamFrame, *wire.StreamDataBlockedFrame, bool) +} + type streamControlFrameGetter interface { getControlFrame(time.Time) (_ ackhandler.Frame, ok, hasMore bool) } @@ -29,7 +33,7 @@ type streamControlFrameGetter interface { type framer struct { mutex sync.Mutex - activeStreams map[protocol.StreamID]sendStreamI + activeStreams map[protocol.StreamID]streamFrameGetter streamQueue ringbuffer.RingBuffer[protocol.StreamID] streamsWithControlFrames map[protocol.StreamID]streamControlFrameGetter @@ -42,7 +46,7 @@ type framer struct { func newFramer(connFlowController flowcontrol.ConnectionFlowController) *framer { return &framer{ - activeStreams: make(map[protocol.StreamID]sendStreamI), + activeStreams: make(map[protocol.StreamID]streamFrameGetter), streamsWithControlFrames: make(map[protocol.StreamID]streamControlFrameGetter), connFlowController: connFlowController, } @@ -214,7 +218,7 @@ func (f *framer) QueuedTooManyControlFrames() bool { return f.queuedTooManyControlFrames } -func (f *framer) AddActiveStream(id protocol.StreamID, str sendStreamI) { +func (f *framer) AddActiveStream(id protocol.StreamID, str streamFrameGetter) { f.mutex.Lock() if _, ok := f.activeStreams[id]; !ok { f.streamQueue.PushBack(id) diff --git a/vendor/github.com/quic-go/quic-go/http3/body.go b/vendor/github.com/quic-go/quic-go/http3/body.go index 8f17bbebe2..356f726a80 100644 --- a/vendor/github.com/quic-go/quic-go/http3/body.go +++ b/vendor/github.com/quic-go/quic-go/http3/body.go @@ -9,24 +9,24 @@ import ( "github.com/quic-go/quic-go" ) -// A Hijacker allows hijacking of the stream creating part of a quic.Connection from a http.ResponseWriter. +// A Hijacker allows hijacking of the stream creating part of a quic.Conn from a http.ResponseWriter. // It is used by WebTransport to create WebTransport streams after a session has been established. type Hijacker interface { - Connection() Connection + Connection() *Conn } var errTooMuchData = errors.New("peer sent too much data") // The body is used in the requestBody (for a http.Request) and the responseBody (for a http.Response). type body struct { - str *stream + str *Stream remainingContentLength int64 violatedContentLength bool hasContentLength bool } -func newBody(str *stream, contentLength int64) *body { +func newBody(str *Stream, contentLength int64) *body { b := &body{str: str} if contentLength >= 0 { b.hasContentLength = true @@ -81,7 +81,7 @@ type requestBody struct { var _ io.ReadCloser = &requestBody{} -func newRequestBody(str *stream, contentLength int64, connCtx context.Context, rcvdSettings <-chan struct{}, getSettings func() *Settings) *requestBody { +func newRequestBody(str *Stream, contentLength int64, connCtx context.Context, rcvdSettings <-chan struct{}, getSettings func() *Settings) *requestBody { return &requestBody{ body: *newBody(str, contentLength), connCtx: connCtx, @@ -102,7 +102,7 @@ type hijackableBody struct { var _ io.ReadCloser = &hijackableBody{} -func newResponseBody(str *stream, contentLength int64, done chan<- struct{}) *hijackableBody { +func newResponseBody(str *Stream, contentLength int64, done chan<- struct{}) *hijackableBody { return &hijackableBody{ body: *newBody(str, contentLength), reqDone: done, diff --git a/vendor/github.com/quic-go/quic-go/http3/client.go b/vendor/github.com/quic-go/quic-go/http3/client.go index 3691d4d792..7cd02bc328 100644 --- a/vendor/github.com/quic-go/quic-go/http3/client.go +++ b/vendor/github.com/quic-go/quic-go/http3/client.go @@ -46,7 +46,7 @@ var defaultQuicConfig = &quic.Config{ // ClientConn is an HTTP/3 client doing requests to a single remote server. type ClientConn struct { - connection + conn *Conn // Enable support for HTTP/3 datagrams (RFC 9297). // If a QUICConfig is set, datagram support also needs to be enabled on the QUIC layer by setting enableDatagrams. @@ -75,16 +75,12 @@ type ClientConn struct { var _ http.RoundTripper = &ClientConn{} -// Deprecated: SingleDestinationRoundTripper was renamed to ClientConn. -// It can be obtained by calling NewClientConn on a Transport. -type SingleDestinationRoundTripper = ClientConn - func newClientConn( - conn quic.Connection, + conn *quic.Conn, enableDatagrams bool, additionalSettings map[uint64]uint64, - streamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error), - uniStreamHijacker func(StreamType, quic.ConnectionTracingID, quic.ReceiveStream, error) (hijacked bool), + streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error), + uniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool), maxResponseHeaderBytes int64, disableCompression bool, logger *slog.Logger, @@ -102,7 +98,7 @@ func newClientConn( } c.decoder = qpack.NewDecoder(func(hf qpack.HeaderField) {}) c.requestWriter = newRequestWriter() - c.connection = *newConnection( + c.conn = newConnection( conn.Context(), conn, c.enableDatagrams, @@ -116,24 +112,24 @@ func newClientConn( if c.logger != nil { c.logger.Debug("Setting up connection failed", "error", err) } - c.CloseWithError(quic.ApplicationErrorCode(ErrCodeInternalError), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeInternalError), "") } }() if streamHijacker != nil { go c.handleBidirectionalStreams(streamHijacker) } - go c.handleUnidirectionalStreams(uniStreamHijacker) + go c.conn.handleUnidirectionalStreams(uniStreamHijacker) return c } // OpenRequestStream opens a new request stream on the HTTP/3 connection. -func (c *ClientConn) OpenRequestStream(ctx context.Context) (RequestStream, error) { - return c.openRequestStream(ctx, c.requestWriter, nil, c.disableCompression, c.maxResponseHeaderBytes) +func (c *ClientConn) OpenRequestStream(ctx context.Context) (*RequestStream, error) { + return c.conn.openRequestStream(ctx, c.requestWriter, nil, c.disableCompression, c.maxResponseHeaderBytes) } func (c *ClientConn) setupConn() error { // open the control stream - str, err := c.OpenUniStream() + str, err := c.conn.OpenUniStream() if err != nil { return err } @@ -145,9 +141,9 @@ func (c *ClientConn) setupConn() error { return err } -func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error)) { +func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error)) { for { - str, err := c.AcceptStream(context.Background()) + str, err := c.conn.conn.AcceptStream(context.Background()) if err != nil { if c.logger != nil { c.logger.Debug("accepting bidirectional stream failed", "error", err) @@ -155,10 +151,10 @@ func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, q return } fp := &frameParser{ - r: str, - conn: &c.connection, + r: str, + closeConn: c.conn.CloseWithError, unknownFrameHandler: func(ft FrameType, e error) (processed bool, err error) { - id := c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) + id := c.conn.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) return streamHijacker(ft, id, str, e) }, } @@ -171,7 +167,7 @@ func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, q c.logger.Debug("error handling stream", "error", err) } } - c.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "received HTTP/3 frame on bidirectional stream") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "received HTTP/3 frame on bidirectional stream") }() } } @@ -201,33 +197,30 @@ func (c *ClientConn) roundTrip(req *http.Request) (*http.Response, error) { req.Method = http.MethodHead default: // wait for the handshake to complete - earlyConn, ok := c.Connection.(quic.EarlyConnection) - if ok { - select { - case <-earlyConn.HandshakeComplete(): - case <-req.Context().Done(): - return nil, req.Context().Err() - } + select { + case <-c.conn.HandshakeComplete(): + case <-req.Context().Done(): + return nil, req.Context().Err() } } // It is only possible to send an Extended CONNECT request once the SETTINGS were received. // See section 3 of RFC 8441. if isExtendedConnectRequest(req) { - connCtx := c.Connection.Context() + connCtx := c.conn.Context() // wait for the server's SETTINGS frame to arrive select { - case <-c.ReceivedSettings(): + case <-c.conn.ReceivedSettings(): case <-connCtx.Done(): return nil, context.Cause(connCtx) } - if !c.Settings().EnableExtendedConnect { + if !c.conn.Settings().EnableExtendedConnect { return nil, errors.New("http3: server didn't enable Extended CONNECT") } } reqDone := make(chan struct{}) - str, err := c.openRequestStream( + str, err := c.conn.openRequestStream( req.Context(), c.requestWriter, reqDone, @@ -261,11 +254,34 @@ func (c *ClientConn) roundTrip(req *http.Request) (*http.Response, error) { return rsp, maybeReplaceError(err) } +// ReceivedSettings returns a channel that is closed once the server's HTTP/3 settings were received. +// Settings can be obtained from the Settings method after the channel was closed. +func (c *ClientConn) ReceivedSettings() <-chan struct{} { + return c.conn.ReceivedSettings() +} + +// Settings returns the HTTP/3 settings for this connection. +// It is only valid to call this function after the channel returned by ReceivedSettings was closed. +func (c *ClientConn) Settings() *Settings { + return c.conn.Settings() +} + +// CloseWithError closes the connection with the given error code and message. +// It is invalid to call this function after the connection was closed. +func (c *ClientConn) CloseWithError(code ErrCode, msg string) error { + return c.conn.CloseWithError(quic.ApplicationErrorCode(code), msg) +} + +// Context returns a context that is cancelled when the connection is closed. +func (c *ClientConn) Context() context.Context { + return c.conn.Context() +} + // cancelingReader reads from the io.Reader. // It cancels writing on the stream if any error other than io.EOF occurs. type cancelingReader struct { r io.Reader - str Stream + str *RequestStream } func (r *cancelingReader) Read(b []byte) (int, error) { @@ -276,7 +292,7 @@ func (r *cancelingReader) Read(b []byte) (int, error) { return n, err } -func (c *ClientConn) sendRequestBody(str Stream, body io.ReadCloser, contentLength int64) error { +func (c *ClientConn) sendRequestBody(str *RequestStream, body io.ReadCloser, contentLength int64) error { defer body.Close() buf := make([]byte, bodyCopyBufferSize) sr := &cancelingReader{str: str, r: body} @@ -300,9 +316,9 @@ func (c *ClientConn) sendRequestBody(str Stream, body io.ReadCloser, contentLeng return err } -func (c *ClientConn) doRequest(req *http.Request, str *requestStream) (*http.Response, error) { +func (c *ClientConn) doRequest(req *http.Request, str *RequestStream) (*http.Response, error) { trace := httptrace.ContextClientTrace(req.Context()) - if err := str.SendRequestHeader(req); err != nil { + if err := str.sendRequestHeader(req); err != nil { traceWroteRequest(trace, err) return nil, err } @@ -357,8 +373,15 @@ func (c *ClientConn) doRequest(req *http.Request, str *requestStream) (*http.Res } break } - connState := c.ConnectionState().TLS + connState := c.conn.ConnectionState().TLS res.TLS = &connState res.Request = req return res, nil } + +// Conn returns the underlying HTTP/3 connection. +// This method is only useful for advanced use cases, such as when the application needs to +// open streams on the HTTP/3 connection (e.g. WebTransport). +func (c *ClientConn) Conn() *Conn { + return c.conn +} diff --git a/vendor/github.com/quic-go/quic-go/http3/conn.go b/vendor/github.com/quic-go/quic-go/http3/conn.go index a2c8ba61e8..63ac9cbe22 100644 --- a/vendor/github.com/quic-go/quic-go/http3/conn.go +++ b/vendor/github.com/quic-go/quic-go/http3/conn.go @@ -20,30 +20,16 @@ import ( "github.com/quic-go/qpack" ) +const maxQuarterStreamID = 1<<60 - 1 + var errGoAway = errors.New("connection in graceful shutdown") -// Connection is an HTTP/3 connection. -// It has all methods from the quic.Connection expect for AcceptStream, AcceptUniStream, +// Conn is an HTTP/3 connection. +// It has all methods from the quic.Conn expect for AcceptStream, AcceptUniStream, // SendDatagram and ReceiveDatagram. -type Connection interface { - OpenStream() (quic.Stream, error) - OpenStreamSync(context.Context) (quic.Stream, error) - OpenUniStream() (quic.SendStream, error) - OpenUniStreamSync(context.Context) (quic.SendStream, error) - LocalAddr() net.Addr - RemoteAddr() net.Addr - CloseWithError(quic.ApplicationErrorCode, string) error - Context() context.Context - ConnectionState() quic.ConnectionState - - // ReceivedSettings returns a channel that is closed once the client's SETTINGS frame was received. - ReceivedSettings() <-chan struct{} - // Settings returns the settings received on this connection. - Settings() *Settings -} +type Conn struct { + conn *quic.Conn -type connection struct { - quic.Connection ctx context.Context perspective protocol.Perspective @@ -54,7 +40,7 @@ type connection struct { decoder *qpack.Decoder streamMx sync.Mutex - streams map[protocol.StreamID]*datagrammer + streams map[protocol.StreamID]*stateTrackingStream lastStreamID protocol.StreamID maxStreamID protocol.StreamID @@ -67,22 +53,22 @@ type connection struct { func newConnection( ctx context.Context, - quicConn quic.Connection, + quicConn *quic.Conn, enableDatagrams bool, perspective protocol.Perspective, logger *slog.Logger, idleTimeout time.Duration, -) *connection { - c := &connection{ +) *Conn { + c := &Conn{ ctx: ctx, - Connection: quicConn, + conn: quicConn, perspective: perspective, logger: logger, idleTimeout: idleTimeout, enableDatagrams: enableDatagrams, decoder: qpack.NewDecoder(func(hf qpack.HeaderField) {}), receivedSettings: make(chan struct{}), - streams: make(map[protocol.StreamID]*datagrammer), + streams: make(map[protocol.StreamID]*stateTrackingStream), maxStreamID: protocol.InvalidStreamID, lastStreamID: protocol.InvalidStreamID, } @@ -92,11 +78,43 @@ func newConnection( return c } -func (c *connection) onIdleTimer() { +func (c *Conn) OpenStream() (*quic.Stream, error) { + return c.conn.OpenStream() +} + +func (c *Conn) OpenStreamSync(ctx context.Context) (*quic.Stream, error) { + return c.conn.OpenStreamSync(ctx) +} + +func (c *Conn) OpenUniStream() (*quic.SendStream, error) { + return c.conn.OpenUniStream() +} + +func (c *Conn) OpenUniStreamSync(ctx context.Context) (*quic.SendStream, error) { + return c.conn.OpenUniStreamSync(ctx) +} + +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +func (c *Conn) HandshakeComplete() <-chan struct{} { + return c.conn.HandshakeComplete() +} + +func (c *Conn) ConnectionState() quic.ConnectionState { + return c.conn.ConnectionState() +} + +func (c *Conn) onIdleTimer() { c.CloseWithError(quic.ApplicationErrorCode(ErrCodeNoError), "idle timeout") } -func (c *connection) clearStream(id quic.StreamID) { +func (c *Conn) clearStream(id quic.StreamID) { c.streamMx.Lock() defer c.streamMx.Unlock() @@ -113,54 +131,58 @@ func (c *connection) clearStream(id quic.StreamID) { } } -func (c *connection) openRequestStream( +func (c *Conn) openRequestStream( ctx context.Context, requestWriter *requestWriter, reqDone chan<- struct{}, disableCompression bool, maxHeaderBytes uint64, -) (*requestStream, error) { - if c.perspective == protocol.PerspectiveClient { - c.streamMx.Lock() - maxStreamID := c.maxStreamID - var nextStreamID quic.StreamID - if c.lastStreamID == protocol.InvalidStreamID { - nextStreamID = 0 - } else { - nextStreamID = c.lastStreamID + 4 - } - c.streamMx.Unlock() - // Streams with stream ID equal to or greater than the stream ID carried in the GOAWAY frame - // will be rejected, see section 5.2 of RFC 9114. - if maxStreamID != protocol.InvalidStreamID && nextStreamID >= maxStreamID { - return nil, errGoAway - } +) (*RequestStream, error) { + c.streamMx.Lock() + maxStreamID := c.maxStreamID + var nextStreamID quic.StreamID + if c.lastStreamID == protocol.InvalidStreamID { + nextStreamID = 0 + } else { + nextStreamID = c.lastStreamID + 4 + } + c.streamMx.Unlock() + // Streams with stream ID equal to or greater than the stream ID carried in the GOAWAY frame + // will be rejected, see section 5.2 of RFC 9114. + if maxStreamID != protocol.InvalidStreamID && nextStreamID >= maxStreamID { + return nil, errGoAway } str, err := c.OpenStreamSync(ctx) if err != nil { return nil, err } - datagrams := newDatagrammer(func(b []byte) error { return c.sendDatagram(str.StreamID(), b) }) + hstr := newStateTrackingStream(str, c, func(b []byte) error { return c.sendDatagram(str.StreamID(), b) }) c.streamMx.Lock() - c.streams[str.StreamID()] = datagrams + c.streams[str.StreamID()] = hstr c.lastStreamID = str.StreamID() c.streamMx.Unlock() - qstr := newStateTrackingStream(str, c, datagrams) rsp := &http.Response{} - hstr := newStream(qstr, c, datagrams, func(r io.Reader, l uint64) error { - hdr, err := c.decodeTrailers(r, l, maxHeaderBytes) - if err != nil { - return err - } - rsp.Trailer = hdr - return nil - }) trace := httptrace.ContextClientTrace(ctx) - return newRequestStream(hstr, requestWriter, reqDone, c.decoder, disableCompression, maxHeaderBytes, rsp, trace), nil + return newRequestStream( + newStream(hstr, c, trace, func(r io.Reader, l uint64) error { + hdr, err := c.decodeTrailers(r, l, maxHeaderBytes) + if err != nil { + return err + } + rsp.Trailer = hdr + return nil + }), + requestWriter, + reqDone, + c.decoder, + disableCompression, + maxHeaderBytes, + rsp, + ), nil } -func (c *connection) decodeTrailers(r io.Reader, l, maxHeaderBytes uint64) (http.Header, error) { +func (c *Conn) decodeTrailers(r io.Reader, l, maxHeaderBytes uint64) (http.Header, error) { if l > maxHeaderBytes { return nil, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", l, maxHeaderBytes) } @@ -176,35 +198,33 @@ func (c *connection) decodeTrailers(r io.Reader, l, maxHeaderBytes uint64) (http return parseTrailers(fields) } -func (c *connection) acceptStream(ctx context.Context) (quic.Stream, *datagrammer, error) { - str, err := c.AcceptStream(ctx) +// only used by the server +func (c *Conn) acceptStream(ctx context.Context) (*stateTrackingStream, error) { + str, err := c.conn.AcceptStream(ctx) if err != nil { - return nil, nil, err + return nil, err } - datagrams := newDatagrammer(func(b []byte) error { return c.sendDatagram(str.StreamID(), b) }) - if c.perspective == protocol.PerspectiveServer { - strID := str.StreamID() - c.streamMx.Lock() - c.streams[strID] = datagrams - if c.idleTimeout > 0 { - if len(c.streams) == 1 { - c.idleTimer.Stop() - } + strID := str.StreamID() + hstr := newStateTrackingStream(str, c, func(b []byte) error { return c.sendDatagram(strID, b) }) + c.streamMx.Lock() + c.streams[strID] = hstr + if c.idleTimeout > 0 { + if len(c.streams) == 1 { + c.idleTimer.Stop() } - c.streamMx.Unlock() - str = newStateTrackingStream(str, c, datagrams) } - return str, datagrams, nil + c.streamMx.Unlock() + return hstr, nil } -func (c *connection) CloseWithError(code quic.ApplicationErrorCode, msg string) error { +func (c *Conn) CloseWithError(code quic.ApplicationErrorCode, msg string) error { if c.idleTimer != nil { c.idleTimer.Stop() } - return c.Connection.CloseWithError(code, msg) + return c.conn.CloseWithError(code, msg) } -func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.ConnectionTracingID, quic.ReceiveStream, error) (hijacked bool)) { +func (c *Conn) handleUnidirectionalStreams(hijack func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool)) { var ( rcvdControlStr atomic.Bool rcvdQPACKEncoderStr atomic.Bool @@ -212,7 +232,7 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co ) for { - str, err := c.AcceptUniStream(context.Background()) + str, err := c.conn.AcceptUniStream(context.Background()) if err != nil { if c.logger != nil { c.logger.Debug("accepting unidirectional stream failed", "error", err) @@ -220,7 +240,7 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co return } - go func(str quic.ReceiveStream) { + go func(str *quic.ReceiveStream) { streamType, err := quicvarint.Read(quicvarint.NewReader(str)) if err != nil { id := c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) @@ -273,7 +293,7 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co } // Only a single control stream is allowed. if isFirstControlStr := rcvdControlStr.CompareAndSwap(false, true); !isFirstControlStr { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream") return } c.handleControlStream(str) @@ -281,21 +301,21 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co } } -func (c *connection) handleControlStream(str quic.ReceiveStream) { - fp := &frameParser{conn: c.Connection, r: str} +func (c *Conn) handleControlStream(str *quic.ReceiveStream) { + fp := &frameParser{closeConn: c.conn.CloseWithError, r: str} f, err := fp.ParseNext() if err != nil { var serr *quic.StreamError if err == io.EOF || errors.As(err, &serr) { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeClosedCriticalStream), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeClosedCriticalStream), "") return } - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "") return } sf, ok := f.(*settingsFrame) if !ok { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeMissingSettings), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeMissingSettings), "") return } c.settings = &Settings{ @@ -331,10 +351,10 @@ func (c *connection) handleControlStream(str quic.ReceiveStream) { if err != nil { var serr *quic.StreamError if err == io.EOF || errors.As(err, &serr) { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeClosedCriticalStream), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeClosedCriticalStream), "") return } - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "") return } // GOAWAY is the only frame allowed at this point: @@ -342,17 +362,17 @@ func (c *connection) handleControlStream(str quic.ReceiveStream) { // * we don't support any extension that might add support for more frames goaway, ok := f.(*goAwayFrame) if !ok { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") return } if goaway.StreamID%4 != 0 { // client-initiated, bidirectional streams - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") return } c.streamMx.Lock() if c.maxStreamID != protocol.InvalidStreamID && goaway.StreamID > c.maxStreamID { c.streamMx.Unlock() - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") + c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") return } c.maxStreamID = goaway.StreamID @@ -367,17 +387,17 @@ func (c *connection) handleControlStream(str quic.ReceiveStream) { } } -func (c *connection) sendDatagram(streamID protocol.StreamID, b []byte) error { +func (c *Conn) sendDatagram(streamID protocol.StreamID, b []byte) error { // TODO: this creates a lot of garbage and an additional copy data := make([]byte, 0, len(b)+8) data = quicvarint.Append(data, uint64(streamID/4)) data = append(data, b...) - return c.SendDatagram(data) + return c.conn.SendDatagram(data) } -func (c *connection) receiveDatagrams() error { +func (c *Conn) receiveDatagrams() error { for { - b, err := c.ReceiveDatagram(context.Background()) + b, err := c.conn.ReceiveDatagram(context.Background()) if err != nil { return err } @@ -397,17 +417,17 @@ func (c *connection) receiveDatagrams() error { if !ok { continue } - dg.enqueue(b[n:]) + dg.enqueueDatagram(b[n:]) } } // ReceivedSettings returns a channel that is closed once the peer's SETTINGS frame was received. // Settings can be optained from the Settings method after the channel was closed. -func (c *connection) ReceivedSettings() <-chan struct{} { return c.receivedSettings } +func (c *Conn) ReceivedSettings() <-chan struct{} { return c.receivedSettings } // Settings returns the settings received on this connection. // It is only valid to call this function after the channel returned by ReceivedSettings was closed. -func (c *connection) Settings() *Settings { return c.settings } +func (c *Conn) Settings() *Settings { return c.settings } // Context returns the context of the underlying QUIC connection. -func (c *connection) Context() context.Context { return c.ctx } +func (c *Conn) Context() context.Context { return c.ctx } diff --git a/vendor/github.com/quic-go/quic-go/http3/datagram.go b/vendor/github.com/quic-go/quic-go/http3/datagram.go deleted file mode 100644 index 6d570e6b00..0000000000 --- a/vendor/github.com/quic-go/quic-go/http3/datagram.go +++ /dev/null @@ -1,98 +0,0 @@ -package http3 - -import ( - "context" - "sync" -) - -const maxQuarterStreamID = 1<<60 - 1 - -const streamDatagramQueueLen = 32 - -type datagrammer struct { - sendDatagram func([]byte) error - - hasData chan struct{} - queue [][]byte // TODO: use a ring buffer - - mx sync.Mutex - sendErr error - receiveErr error -} - -func newDatagrammer(sendDatagram func([]byte) error) *datagrammer { - return &datagrammer{ - sendDatagram: sendDatagram, - hasData: make(chan struct{}, 1), - } -} - -func (d *datagrammer) SetReceiveError(err error) { - d.mx.Lock() - defer d.mx.Unlock() - - d.receiveErr = err - d.signalHasData() -} - -func (d *datagrammer) SetSendError(err error) { - d.mx.Lock() - defer d.mx.Unlock() - - d.sendErr = err -} - -func (d *datagrammer) Send(b []byte) error { - d.mx.Lock() - sendErr := d.sendErr - d.mx.Unlock() - if sendErr != nil { - return sendErr - } - - return d.sendDatagram(b) -} - -func (d *datagrammer) signalHasData() { - select { - case d.hasData <- struct{}{}: - default: - } -} - -func (d *datagrammer) enqueue(data []byte) { - d.mx.Lock() - defer d.mx.Unlock() - - if d.receiveErr != nil { - return - } - if len(d.queue) >= streamDatagramQueueLen { - return - } - d.queue = append(d.queue, data) - d.signalHasData() -} - -func (d *datagrammer) Receive(ctx context.Context) ([]byte, error) { -start: - d.mx.Lock() - if len(d.queue) >= 1 { - data := d.queue[0] - d.queue = d.queue[1:] - d.mx.Unlock() - return data, nil - } - if receiveErr := d.receiveErr; receiveErr != nil { - d.mx.Unlock() - return nil, receiveErr - } - d.mx.Unlock() - - select { - case <-ctx.Done(): - return nil, context.Cause(ctx) - case <-d.hasData: - } - goto start -} diff --git a/vendor/github.com/quic-go/quic-go/http3/frames.go b/vendor/github.com/quic-go/quic-go/http3/frames.go index b54afb313c..e5149cb21b 100644 --- a/vendor/github.com/quic-go/quic-go/http3/frames.go +++ b/vendor/github.com/quic-go/quic-go/http3/frames.go @@ -21,7 +21,7 @@ var errHijacked = errors.New("hijacked") type frameParser struct { r io.Reader - conn quic.Connection + closeConn func(quic.ApplicationErrorCode, string) error unknownFrameHandler unknownFrameHandlerFunc } @@ -70,7 +70,7 @@ func (p *frameParser) ParseNext() (frame, error) { return parseGoAwayFrame(qr, l) case 0xd: // MAX_PUSH_ID case 0x2, 0x6, 0x8, 0x9: - p.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") + p.closeConn(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") return nil, fmt.Errorf("http3: reserved frame type: %d", t) } // skip over unknown frames diff --git a/vendor/github.com/quic-go/quic-go/http3/http_stream.go b/vendor/github.com/quic-go/quic-go/http3/http_stream.go deleted file mode 100644 index e030ab9705..0000000000 --- a/vendor/github.com/quic-go/quic-go/http3/http_stream.go +++ /dev/null @@ -1,294 +0,0 @@ -package http3 - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptrace" - - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/internal/protocol" - - "github.com/quic-go/qpack" -) - -// A Stream is an HTTP/3 request stream. -// When writing to and reading from the stream, data is framed in HTTP/3 DATA frames. -type Stream interface { - quic.Stream - - SendDatagram([]byte) error - ReceiveDatagram(context.Context) ([]byte, error) -} - -// A RequestStream is an HTTP/3 request stream. -// When writing to and reading from the stream, data is framed in HTTP/3 DATA frames. -type RequestStream interface { - Stream - - // SendRequestHeader sends the HTTP request. - // It is invalid to call it more than once. - // It is invalid to call it after Write has been called. - SendRequestHeader(req *http.Request) error - - // ReadResponse reads the HTTP response from the stream. - // It is invalid to call it more than once. - // It doesn't set Response.Request and Response.TLS. - // It is invalid to call it after Read has been called. - ReadResponse() (*http.Response, error) -} - -type stream struct { - quic.Stream - conn *connection - - buf []byte // used as a temporary buffer when writing the HTTP/3 frame headers - - bytesRemainingInFrame uint64 - - datagrams *datagrammer - - parseTrailer func(io.Reader, uint64) error - parsedTrailer bool -} - -var _ Stream = &stream{} - -func newStream(str quic.Stream, conn *connection, datagrams *datagrammer, parseTrailer func(io.Reader, uint64) error) *stream { - return &stream{ - Stream: str, - conn: conn, - buf: make([]byte, 16), - datagrams: datagrams, - parseTrailer: parseTrailer, - } -} - -func (s *stream) Read(b []byte) (int, error) { - fp := &frameParser{ - r: s.Stream, - conn: s.conn, - } - if s.bytesRemainingInFrame == 0 { - parseLoop: - for { - frame, err := fp.ParseNext() - if err != nil { - return 0, err - } - switch f := frame.(type) { - case *dataFrame: - if s.parsedTrailer { - return 0, errors.New("DATA frame received after trailers") - } - s.bytesRemainingInFrame = f.Length - break parseLoop - case *headersFrame: - if s.conn.perspective == protocol.PerspectiveServer { - continue - } - if s.parsedTrailer { - return 0, errors.New("additional HEADERS frame received after trailers") - } - s.parsedTrailer = true - return 0, s.parseTrailer(s.Stream, f.Length) - default: - s.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") - // parseNextFrame skips over unknown frame types - // Therefore, this condition is only entered when we parsed another known frame type. - return 0, fmt.Errorf("peer sent an unexpected frame: %T", f) - } - } - } - - var n int - var err error - if s.bytesRemainingInFrame < uint64(len(b)) { - n, err = s.Stream.Read(b[:s.bytesRemainingInFrame]) - } else { - n, err = s.Stream.Read(b) - } - s.bytesRemainingInFrame -= uint64(n) - return n, err -} - -func (s *stream) hasMoreData() bool { - return s.bytesRemainingInFrame > 0 -} - -func (s *stream) Write(b []byte) (int, error) { - s.buf = s.buf[:0] - s.buf = (&dataFrame{Length: uint64(len(b))}).Append(s.buf) - if _, err := s.Stream.Write(s.buf); err != nil { - return 0, err - } - return s.Stream.Write(b) -} - -func (s *stream) writeUnframed(b []byte) (int, error) { - return s.Stream.Write(b) -} - -func (s *stream) StreamID() protocol.StreamID { - return s.Stream.StreamID() -} - -// The stream conforms to the quic.Stream interface, but instead of writing to and reading directly -// from the QUIC stream, it writes to and reads from the HTTP stream. -type requestStream struct { - *stream - - responseBody io.ReadCloser // set by ReadResponse - - decoder *qpack.Decoder - requestWriter *requestWriter - maxHeaderBytes uint64 - reqDone chan<- struct{} - disableCompression bool - response *http.Response - trace *httptrace.ClientTrace - - sentRequest bool - requestedGzip bool - isConnect bool - firstByte bool -} - -var _ RequestStream = &requestStream{} - -func newRequestStream( - str *stream, - requestWriter *requestWriter, - reqDone chan<- struct{}, - decoder *qpack.Decoder, - disableCompression bool, - maxHeaderBytes uint64, - rsp *http.Response, - trace *httptrace.ClientTrace, -) *requestStream { - return &requestStream{ - stream: str, - requestWriter: requestWriter, - reqDone: reqDone, - decoder: decoder, - disableCompression: disableCompression, - maxHeaderBytes: maxHeaderBytes, - response: rsp, - trace: trace, - } -} - -func (s *requestStream) Read(b []byte) (int, error) { - if s.responseBody == nil { - return 0, errors.New("http3: invalid use of RequestStream.Read: need to call ReadResponse first") - } - return s.responseBody.Read(b) -} - -func (s *requestStream) SendRequestHeader(req *http.Request) error { - if s.sentRequest { - return errors.New("http3: invalid duplicate use of SendRequestHeader") - } - if !s.disableCompression && req.Method != http.MethodHead && - req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" { - s.requestedGzip = true - } - s.isConnect = req.Method == http.MethodConnect - s.sentRequest = true - return s.requestWriter.WriteRequestHeader(s.Stream, req, s.requestedGzip) -} - -func (s *requestStream) ReadResponse() (*http.Response, error) { - fp := &frameParser{ - conn: s.conn, - r: &tracingReader{ - Reader: s.Stream, - first: &s.firstByte, - trace: s.trace, - }, - } - frame, err := fp.ParseNext() - if err != nil { - s.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) - s.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) - return nil, fmt.Errorf("http3: parsing frame failed: %w", err) - } - hf, ok := frame.(*headersFrame) - if !ok { - s.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame") - return nil, errors.New("http3: expected first frame to be a HEADERS frame") - } - if hf.Length > s.maxHeaderBytes { - s.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) - s.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) - return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes) - } - headerBlock := make([]byte, hf.Length) - if _, err := io.ReadFull(s.Stream, headerBlock); err != nil { - s.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete)) - s.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete)) - return nil, fmt.Errorf("http3: failed to read response headers: %w", err) - } - hfs, err := s.decoder.DecodeFull(headerBlock) - if err != nil { - // TODO: use the right error code - s.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeGeneralProtocolError), "") - return nil, fmt.Errorf("http3: failed to decode response headers: %w", err) - } - res := s.response - if err := updateResponseFromHeaders(res, hfs); err != nil { - s.CancelRead(quic.StreamErrorCode(ErrCodeMessageError)) - s.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError)) - return nil, fmt.Errorf("http3: invalid response: %w", err) - } - - // Check that the server doesn't send more data in DATA frames than indicated by the Content-Length header (if set). - // See section 4.1.2 of RFC 9114. - respBody := newResponseBody(s.stream, res.ContentLength, s.reqDone) - - // Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2. - isInformational := res.StatusCode >= 100 && res.StatusCode < 200 - isNoContent := res.StatusCode == http.StatusNoContent - isSuccessfulConnect := s.isConnect && res.StatusCode >= 200 && res.StatusCode < 300 - if (isInformational || isNoContent || isSuccessfulConnect) && res.ContentLength == -1 { - res.ContentLength = 0 - } - if s.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { - res.Header.Del("Content-Encoding") - res.Header.Del("Content-Length") - res.ContentLength = -1 - s.responseBody = newGzipReader(respBody) - res.Uncompressed = true - } else { - s.responseBody = respBody - } - res.Body = s.responseBody - return res, nil -} - -func (s *stream) SendDatagram(b []byte) error { - // TODO: reject if datagrams are not negotiated (yet) - return s.datagrams.Send(b) -} - -func (s *stream) ReceiveDatagram(ctx context.Context) ([]byte, error) { - // TODO: reject if datagrams are not negotiated (yet) - return s.datagrams.Receive(ctx) -} - -type tracingReader struct { - io.Reader - first *bool - trace *httptrace.ClientTrace -} - -func (r *tracingReader) Read(b []byte) (int, error) { - n, err := r.Reader.Read(b) - if n > 0 && r.first != nil && !*r.first { - traceGotFirstResponseByte(r.trace) - *r.first = true - } - return n, err -} diff --git a/vendor/github.com/quic-go/quic-go/http3/mockgen.go b/vendor/github.com/quic-go/quic-go/http3/mockgen.go index 1d790e11db..72c857018b 100644 --- a/vendor/github.com/quic-go/quic-go/http3/mockgen.go +++ b/vendor/github.com/quic-go/quic-go/http3/mockgen.go @@ -5,4 +5,7 @@ package http3 //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -mock_names=TestClientConnInterface=MockClientConn -package http3 -destination mock_clientconn_test.go github.com/quic-go/quic-go/http3 TestClientConnInterface" type TestClientConnInterface = clientConn -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener" +//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -mock_names=DatagramStream=MockDatagramStream -package http3 -destination mock_datagram_stream_test.go github.com/quic-go/quic-go/http3 DatagramStream" +type DatagramStream = datagramStream + +//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package http3 -destination mock_quic_listener_test.go github.com/quic-go/quic-go/http3 QUICListener" diff --git a/vendor/github.com/quic-go/quic-go/http3/response_writer.go b/vendor/github.com/quic-go/quic-go/http3/response_writer.go index bcfc85c2fd..5dc0ad3013 100644 --- a/vendor/github.com/quic-go/quic-go/http3/response_writer.go +++ b/vendor/github.com/quic-go/quic-go/http3/response_writer.go @@ -17,7 +17,7 @@ import ( // The HTTPStreamer allows taking over a HTTP/3 stream. The interface is implemented by the http.ResponseWriter. // When a stream is taken over, it's the caller's responsibility to close the stream. type HTTPStreamer interface { - HTTPStream() Stream + HTTPStream() *Stream } // The maximum length of an encoded HTTP/3 frame header is 16: @@ -27,9 +27,9 @@ const frameHeaderLen = 16 const maxSmallResponseSize = 4096 type responseWriter struct { - str *stream + str *Stream - conn Connection + conn *Conn header http.Header trailers map[string]struct{} buf []byte @@ -65,7 +65,7 @@ var ( } = &responseWriter{} ) -func newResponseWriter(str *stream, conn Connection, isHead bool, logger *slog.Logger) *responseWriter { +func newResponseWriter(str *Stream, conn *Conn, isHead bool, logger *slog.Logger) *responseWriter { return &responseWriter{ str: str, conn: conn, @@ -331,7 +331,7 @@ func (w *responseWriter) writeTrailers() error { return err } -func (w *responseWriter) HTTPStream() Stream { +func (w *responseWriter) HTTPStream() *Stream { w.hijacked = true w.Flush() return w.str @@ -339,7 +339,7 @@ func (w *responseWriter) HTTPStream() Stream { func (w *responseWriter) wasStreamHijacked() bool { return w.hijacked } -func (w *responseWriter) Connection() Connection { +func (w *responseWriter) Connection() *Conn { return w.conn } diff --git a/vendor/github.com/quic-go/quic-go/http3/server.go b/vendor/github.com/quic-go/quic-go/http3/server.go index 5e40581458..8d53a72467 100644 --- a/vendor/github.com/quic-go/quic-go/http3/server.go +++ b/vendor/github.com/quic-go/quic-go/http3/server.go @@ -37,14 +37,14 @@ const ( streamTypeQPACKDecoderStream = 3 ) -// A QUICEarlyListener listens for incoming QUIC connections. -type QUICEarlyListener interface { - Accept(context.Context) (quic.EarlyConnection, error) +// A QUICListener listens for incoming QUIC connections. +type QUICListener interface { + Accept(context.Context) (*quic.Conn, error) Addr() net.Addr io.Closer } -var _ QUICEarlyListener = &quic.EarlyListener{} +var _ QUICListener = &quic.EarlyListener{} // ConfigureTLSConfig creates a new tls.Config which can be used // to create a quic.Listener meant for serving HTTP/3. @@ -92,7 +92,7 @@ var RemoteAddrContextKey = &contextKey{"remote-addr"} // listener contains info about specific listener added with addListener type listener struct { - ln *QUICEarlyListener + ln *QUICListener port int // 0 means that no info about port is available // if this listener was constructed by the application, it won't be closed when the server is closed @@ -156,12 +156,12 @@ type Server struct { // Callers can either ignore the frame and return control of the stream back to HTTP/3 // (by returning hijacked false). // Alternatively, callers can take over the QUIC stream (by returning hijacked true). - StreamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error) + StreamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error) // UniStreamHijacker, when set, is called for unknown unidirectional stream of unknown stream type. // If parsing the stream type fails, the error is passed to the callback. // In that case, the stream type will not be set. - UniStreamHijacker func(StreamType, quic.ConnectionTracingID, quic.ReceiveStream, error) (hijacked bool) + UniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool) // IdleTimeout specifies how long until idle clients connection should be // closed. Idle refers only to the HTTP/3 layer, activity at the QUIC layer @@ -171,7 +171,7 @@ type Server struct { // ConnContext optionally specifies a function that modifies the context used for a new connection c. // The provided ctx has a ServerContextKey value. - ConnContext func(ctx context.Context, c quic.Connection) context.Context + ConnContext func(ctx context.Context, c *quic.Conn) context.Context Logger *slog.Logger @@ -253,7 +253,7 @@ func (s *Server) decreaseConnCount() { } // ServeQUICConn serves a single QUIC connection. -func (s *Server) ServeQUICConn(conn quic.Connection) error { +func (s *Server) ServeQUICConn(conn *quic.Conn) error { s.mutex.Lock() if s.closed { s.mutex.Unlock() @@ -274,7 +274,7 @@ func (s *Server) ServeQUICConn(conn quic.Connection) error { // and use it to construct a http3-friendly QUIC listener. // Closing the server does close the listener. // ServeListener always returns a non-nil error. After Shutdown or Close, the returned error is http.ErrServerClosed. -func (s *Server) ServeListener(ln QUICEarlyListener) error { +func (s *Server) ServeListener(ln QUICListener) error { s.mutex.Lock() if err := s.addListener(&ln, false); err != nil { s.mutex.Unlock() @@ -286,7 +286,7 @@ func (s *Server) ServeListener(ln QUICEarlyListener) error { return s.serveListener(ln) } -func (s *Server) serveListener(ln QUICEarlyListener) error { +func (s *Server) serveListener(ln QUICListener) error { for { conn, err := ln.Accept(s.graceCtx) // server closed @@ -310,7 +310,7 @@ func (s *Server) serveListener(ln QUICEarlyListener) error { var errServerWithoutTLSConfig = errors.New("use of http3.Server without TLSConfig") -func (s *Server) setupListenerForConn(tlsConf *tls.Config, conn net.PacketConn) (*QUICEarlyListener, error) { +func (s *Server) setupListenerForConn(tlsConf *tls.Config, conn net.PacketConn) (*QUICListener, error) { if tlsConf == nil { return nil, errServerWithoutTLSConfig } @@ -333,7 +333,7 @@ func (s *Server) setupListenerForConn(tlsConf *tls.Config, conn net.PacketConn) return nil, http.ErrServerClosed } - var ln QUICEarlyListener + var ln QUICListener var err error if conn == nil { addr := s.Addr @@ -404,7 +404,7 @@ func (s *Server) generateAltSvcHeader() { s.altSvcHeader = strings.Join(altSvc, ",") } -func (s *Server) addListener(l *QUICEarlyListener, createdLocally bool) error { +func (s *Server) addListener(l *QUICListener, createdLocally bool) error { if s.closed { return http.ErrServerClosed } @@ -425,7 +425,7 @@ func (s *Server) addListener(l *QUICEarlyListener, createdLocally bool) error { return nil } -func (s *Server) removeListener(l *QUICEarlyListener) { +func (s *Server) removeListener(l *QUICListener) { s.mutex.Lock() defer s.mutex.Unlock() @@ -437,7 +437,7 @@ func (s *Server) removeListener(l *QUICEarlyListener) { // handleConn handles the HTTP/3 exchange on a QUIC connection. // It blocks until all HTTP handlers for all streams have returned. -func (s *Server) handleConn(conn quic.Connection) error { +func (s *Server) handleConn(conn *quic.Conn) error { // open the control stream and send a SETTINGS frame, it's also used to send a GOAWAY frame later // when the server is gracefully closed ctrlStr, err := conn.OpenUniStream() @@ -486,7 +486,7 @@ func (s *Server) handleConn(conn quic.Connection) error { // * before graceful shutdown: s.graceCtx // * after graceful shutdown: s.closeCtx // This allows us to keep accepting (and resetting) streams after graceful shutdown has started. - str, datagrams, err := hconn.acceptStream(ctx) + str, err := hconn.acceptStream(ctx) if err != nil { // the underlying connection was closed (by either side) if hconn.Context().Err() != nil { @@ -536,7 +536,7 @@ func (s *Server) handleConn(conn quic.Connection) error { // handleRequest will return once the request has been handled, // or the underlying connection is closed defer wg.Done() - s.handleRequest(hconn, str, datagrams, hconn.decoder) + s.handleRequest(hconn, str, hconn.decoder) }() } wg.Wait() @@ -550,19 +550,19 @@ func (s *Server) maxHeaderBytes() uint64 { return uint64(s.MaxHeaderBytes) } -func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *datagrammer, decoder *qpack.Decoder) { +func (s *Server) handleRequest(conn *Conn, str datagramStream, decoder *qpack.Decoder) { var ufh unknownFrameHandlerFunc if s.StreamHijacker != nil { ufh = func(ft FrameType, e error) (processed bool, err error) { return s.StreamHijacker( ft, conn.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID), - str, + str.QUICStream(), e, ) } } - fp := &frameParser{conn: conn, r: str, unknownFrameHandler: ufh} + fp := &frameParser{closeConn: conn.CloseWithError, r: str, unknownFrameHandler: ufh} frame, err := fp.ParseNext() if err != nil { if !errors.Is(err, errHijacked) { @@ -610,7 +610,7 @@ func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *dat if _, ok := req.Header["Content-Length"]; ok && req.ContentLength >= 0 { contentLength = req.ContentLength } - hstr := newStream(str, conn, datagrams, nil) + hstr := newStream(str, conn, nil, nil) body := newRequestBody(hstr, contentLength, conn.Context(), conn.ReceivedSettings(), conn.Settings) req.Body = body diff --git a/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go b/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go index 6edbeedfa4..6c7fa52d77 100644 --- a/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go +++ b/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go @@ -9,7 +9,7 @@ import ( "github.com/quic-go/quic-go" ) -var _ quic.Stream = &stateTrackingStream{} +const streamDatagramQueueLen = 32 // stateTrackingStream is an implementation of quic.Stream that delegates // to an underlying stream @@ -19,30 +19,31 @@ var _ quic.Stream = &stateTrackingStream{} // parent connection, this is done through the streamClearer interface when // both the send and receive sides are closed type stateTrackingStream struct { - quic.Stream + *quic.Stream + + sendDatagram func([]byte) error + hasData chan struct{} + queue [][]byte // TODO: use a ring buffer mx sync.Mutex sendErr error recvErr error clearer streamClearer - setter errorSetter } +var _ datagramStream = &stateTrackingStream{} + type streamClearer interface { clearStream(quic.StreamID) } -type errorSetter interface { - SetSendError(error) - SetReceiveError(error) -} - -func newStateTrackingStream(s quic.Stream, clearer streamClearer, setter errorSetter) *stateTrackingStream { +func newStateTrackingStream(s *quic.Stream, clearer streamClearer, sendDatagram func([]byte) error) *stateTrackingStream { t := &stateTrackingStream{ - Stream: s, - clearer: clearer, - setter: setter, + Stream: s, + clearer: clearer, + sendDatagram: sendDatagram, + hasData: make(chan struct{}, 1), } context.AfterFunc(s.Context(), func() { @@ -62,8 +63,6 @@ func (s *stateTrackingStream) closeSend(e error) { if s.recvErr != nil { s.clearer.clearStream(s.StreamID()) } - - s.setter.SetSendError(e) s.sendErr = e } } @@ -78,9 +77,8 @@ func (s *stateTrackingStream) closeReceive(e error) { if s.sendErr != nil { s.clearer.clearStream(s.StreamID()) } - - s.setter.SetReceiveError(e) s.recvErr = e + s.signalHasDatagram() } } @@ -114,3 +112,62 @@ func (s *stateTrackingStream) Read(b []byte) (int, error) { } return n, err } + +func (s *stateTrackingStream) SendDatagram(b []byte) error { + s.mx.Lock() + sendErr := s.sendErr + s.mx.Unlock() + if sendErr != nil { + return sendErr + } + + return s.sendDatagram(b) +} + +func (s *stateTrackingStream) signalHasDatagram() { + select { + case s.hasData <- struct{}{}: + default: + } +} + +func (s *stateTrackingStream) enqueueDatagram(data []byte) { + s.mx.Lock() + defer s.mx.Unlock() + + if s.recvErr != nil { + return + } + if len(s.queue) >= streamDatagramQueueLen { + return + } + s.queue = append(s.queue, data) + s.signalHasDatagram() +} + +func (s *stateTrackingStream) ReceiveDatagram(ctx context.Context) ([]byte, error) { +start: + s.mx.Lock() + if len(s.queue) > 0 { + data := s.queue[0] + s.queue = s.queue[1:] + s.mx.Unlock() + return data, nil + } + if receiveErr := s.recvErr; receiveErr != nil { + s.mx.Unlock() + return nil, receiveErr + } + s.mx.Unlock() + + select { + case <-ctx.Done(): + return nil, context.Cause(ctx) + case <-s.hasData: + } + goto start +} + +func (s *stateTrackingStream) QUICStream() *quic.Stream { + return s.Stream +} diff --git a/vendor/github.com/quic-go/quic-go/http3/stream.go b/vendor/github.com/quic-go/quic-go/http3/stream.go new file mode 100644 index 0000000000..a1dafa11dc --- /dev/null +++ b/vendor/github.com/quic-go/quic-go/http3/stream.go @@ -0,0 +1,375 @@ +package http3 + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptrace" + "time" + + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/internal/protocol" + + "github.com/quic-go/qpack" +) + +type datagramStream interface { + io.ReadWriteCloser + CancelRead(quic.StreamErrorCode) + CancelWrite(quic.StreamErrorCode) + StreamID() quic.StreamID + Context() context.Context + SetDeadline(time.Time) error + SetReadDeadline(time.Time) error + SetWriteDeadline(time.Time) error + SendDatagram(b []byte) error + ReceiveDatagram(ctx context.Context) ([]byte, error) + + QUICStream() *quic.Stream +} + +// A Stream is an HTTP/3 stream. +// +// When writing to and reading from the stream, data is framed in HTTP/3 DATA frames. +type Stream struct { + datagramStream + conn *Conn + frameParser *frameParser + + buf []byte // used as a temporary buffer when writing the HTTP/3 frame headers + + bytesRemainingInFrame uint64 + + parseTrailer func(io.Reader, uint64) error + parsedTrailer bool +} + +func newStream(str datagramStream, conn *Conn, trace *httptrace.ClientTrace, parseTrailer func(io.Reader, uint64) error) *Stream { + return &Stream{ + datagramStream: str, + conn: conn, + buf: make([]byte, 16), + parseTrailer: parseTrailer, + frameParser: &frameParser{ + closeConn: conn.CloseWithError, + r: &tracingReader{Reader: str, trace: trace}, + }, + } +} + +func (s *Stream) Read(b []byte) (int, error) { + fp := &frameParser{ + r: s.datagramStream, + closeConn: s.conn.CloseWithError, + } + if s.bytesRemainingInFrame == 0 { + parseLoop: + for { + frame, err := fp.ParseNext() + if err != nil { + return 0, err + } + switch f := frame.(type) { + case *dataFrame: + if s.parsedTrailer { + return 0, errors.New("DATA frame received after trailers") + } + s.bytesRemainingInFrame = f.Length + break parseLoop + case *headersFrame: + if s.conn.perspective == protocol.PerspectiveServer { + continue + } + if s.parsedTrailer { + return 0, errors.New("additional HEADERS frame received after trailers") + } + s.parsedTrailer = true + return 0, s.parseTrailer(s.datagramStream, f.Length) + default: + s.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "") + // parseNextFrame skips over unknown frame types + // Therefore, this condition is only entered when we parsed another known frame type. + return 0, fmt.Errorf("peer sent an unexpected frame: %T", f) + } + } + } + + var n int + var err error + if s.bytesRemainingInFrame < uint64(len(b)) { + n, err = s.datagramStream.Read(b[:s.bytesRemainingInFrame]) + } else { + n, err = s.datagramStream.Read(b) + } + s.bytesRemainingInFrame -= uint64(n) + return n, err +} + +func (s *Stream) hasMoreData() bool { + return s.bytesRemainingInFrame > 0 +} + +func (s *Stream) Write(b []byte) (int, error) { + s.buf = s.buf[:0] + s.buf = (&dataFrame{Length: uint64(len(b))}).Append(s.buf) + if _, err := s.datagramStream.Write(s.buf); err != nil { + return 0, err + } + return s.datagramStream.Write(b) +} + +func (s *Stream) writeUnframed(b []byte) (int, error) { + return s.datagramStream.Write(b) +} + +func (s *Stream) StreamID() protocol.StreamID { + return s.datagramStream.StreamID() +} + +func (s *Stream) SendDatagram(b []byte) error { + // TODO: reject if datagrams are not negotiated (yet) + return s.datagramStream.SendDatagram(b) +} + +func (s *Stream) ReceiveDatagram(ctx context.Context) ([]byte, error) { + // TODO: reject if datagrams are not negotiated (yet) + return s.datagramStream.ReceiveDatagram(ctx) +} + +// A RequestStream is a low-level abstraction representing an HTTP/3 request stream. +// It decouples sending of the HTTP request from reading the HTTP response, allowing +// the application to optimistically use the stream (and, for example, send datagrams) +// before receiving the response. +// +// This is only needed for advanced use case, e.g. WebTransport and the various +// MASQUE proxying protocols. +type RequestStream struct { + str *Stream + + responseBody io.ReadCloser // set by ReadResponse + + decoder *qpack.Decoder + requestWriter *requestWriter + maxHeaderBytes uint64 + reqDone chan<- struct{} + disableCompression bool + response *http.Response + + sentRequest bool + requestedGzip bool + isConnect bool +} + +func newRequestStream( + str *Stream, + requestWriter *requestWriter, + reqDone chan<- struct{}, + decoder *qpack.Decoder, + disableCompression bool, + maxHeaderBytes uint64, + rsp *http.Response, +) *RequestStream { + return &RequestStream{ + str: str, + requestWriter: requestWriter, + reqDone: reqDone, + decoder: decoder, + disableCompression: disableCompression, + maxHeaderBytes: maxHeaderBytes, + response: rsp, + } +} + +// Read reads data from the underlying stream. +// +// It can only be used after the request has been sent (using SendRequestHeader) +// and the response has been consumed (using ReadResponse). +func (s *RequestStream) Read(b []byte) (int, error) { + if s.responseBody == nil { + return 0, errors.New("http3: invalid use of RequestStream.Read before ReadResponse") + } + return s.responseBody.Read(b) +} + +// StreamID returns the QUIC stream ID of the underlying QUIC stream. +func (s *RequestStream) StreamID() protocol.StreamID { + return s.str.StreamID() +} + +// Write writes data to the stream. +// +// It can only be used after the request has been sent (using SendRequestHeader). +func (s *RequestStream) Write(b []byte) (int, error) { + if !s.sentRequest { + return 0, errors.New("http3: invalid use of RequestStream.Write before SendRequestHeader") + } + return s.str.Write(b) +} + +// Close closes the send-direction of the stream. +// It does not close the receive-direction of the stream. +func (s *RequestStream) Close() error { + return s.str.Close() +} + +// CancelRead aborts receiving on this stream. +// See [quic.Stream.CancelRead] for more details. +func (s *RequestStream) CancelRead(errorCode quic.StreamErrorCode) { + s.str.CancelRead(errorCode) +} + +// CancelWrite aborts sending on this stream. +// See [quic.Stream.CancelWrite] for more details. +func (s *RequestStream) CancelWrite(errorCode quic.StreamErrorCode) { + s.str.CancelWrite(errorCode) +} + +// Context returns a context derived from the underlying QUIC stream's context. +// See [quic.Stream.Context] for more details. +func (s *RequestStream) Context() context.Context { + return s.str.Context() +} + +// SetReadDeadline sets the deadline for Read calls. +func (s *RequestStream) SetReadDeadline(t time.Time) error { + return s.str.SetReadDeadline(t) +} + +// SetWriteDeadline sets the deadline for Write calls. +func (s *RequestStream) SetWriteDeadline(t time.Time) error { + return s.str.SetWriteDeadline(t) +} + +// SetDeadline sets the read and write deadlines associated with the stream. +// It is equivalent to calling both SetReadDeadline and SetWriteDeadline. +func (s *RequestStream) SetDeadline(t time.Time) error { + return s.str.SetDeadline(t) +} + +// SendDatagrams send a new HTTP Datagram (RFC 9297). +// +// It is only possible to send datagrams if the server enabled support for this extension. +// It is recommended (though not required) to send the request before calling this method, +// as the server might drop datagrams which it can't associate with an existing request. +func (s *RequestStream) SendDatagram(b []byte) error { + return s.str.SendDatagram(b) +} + +// ReceiveDatagram receives HTTP Datagrams (RFC 9297). +// +// It is only possible if support for HTTP Datagrams was enabled, using the EnableDatagram +// option on the [Transport]. +func (s *RequestStream) ReceiveDatagram(ctx context.Context) ([]byte, error) { + return s.str.ReceiveDatagram(ctx) +} + +// SendRequestHeader sends the HTTP request. +// +// It can only used for requests that don't have a request body. +// It is invalid to call it more than once. +// It is invalid to call it after Write has been called. +func (s *RequestStream) SendRequestHeader(req *http.Request) error { + if req.Body != nil && req.Body != http.NoBody { + return errors.New("http3: invalid use of RequestStream.SendRequestHeader with a request that has a request body") + } + return s.sendRequestHeader(req) +} + +func (s *RequestStream) sendRequestHeader(req *http.Request) error { + if s.sentRequest { + return errors.New("http3: invalid duplicate use of RequestStream.SendRequestHeader") + } + if !s.disableCompression && req.Method != http.MethodHead && + req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" { + s.requestedGzip = true + } + s.isConnect = req.Method == http.MethodConnect + s.sentRequest = true + return s.requestWriter.WriteRequestHeader(s.str.datagramStream, req, s.requestedGzip) +} + +// ReadResponse reads the HTTP response from the stream. +// +// It must be called after sending the request (using SendRequestHeader). +// It is invalid to call it more than once. +// It doesn't set Response.Request and Response.TLS. +// It is invalid to call it after Read has been called. +func (s *RequestStream) ReadResponse() (*http.Response, error) { + if !s.sentRequest { + return nil, errors.New("http3: invalid duplicate use of RequestStream.ReadResponse before SendRequestHeader") + } + frame, err := s.str.frameParser.ParseNext() + if err != nil { + s.str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) + s.str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) + return nil, fmt.Errorf("http3: parsing frame failed: %w", err) + } + hf, ok := frame.(*headersFrame) + if !ok { + s.str.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame") + return nil, errors.New("http3: expected first frame to be a HEADERS frame") + } + if hf.Length > s.maxHeaderBytes { + s.str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) + s.str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) + return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes) + } + headerBlock := make([]byte, hf.Length) + if _, err := io.ReadFull(s.str.datagramStream, headerBlock); err != nil { + s.str.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete)) + s.str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete)) + return nil, fmt.Errorf("http3: failed to read response headers: %w", err) + } + hfs, err := s.decoder.DecodeFull(headerBlock) + if err != nil { + // TODO: use the right error code + s.str.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeGeneralProtocolError), "") + return nil, fmt.Errorf("http3: failed to decode response headers: %w", err) + } + res := s.response + if err := updateResponseFromHeaders(res, hfs); err != nil { + s.str.CancelRead(quic.StreamErrorCode(ErrCodeMessageError)) + s.str.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError)) + return nil, fmt.Errorf("http3: invalid response: %w", err) + } + + // Check that the server doesn't send more data in DATA frames than indicated by the Content-Length header (if set). + // See section 4.1.2 of RFC 9114. + respBody := newResponseBody(s.str, res.ContentLength, s.reqDone) + + // Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2. + isInformational := res.StatusCode >= 100 && res.StatusCode < 200 + isNoContent := res.StatusCode == http.StatusNoContent + isSuccessfulConnect := s.isConnect && res.StatusCode >= 200 && res.StatusCode < 300 + if (isInformational || isNoContent || isSuccessfulConnect) && res.ContentLength == -1 { + res.ContentLength = 0 + } + if s.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { + res.Header.Del("Content-Encoding") + res.Header.Del("Content-Length") + res.ContentLength = -1 + s.responseBody = newGzipReader(respBody) + res.Uncompressed = true + } else { + s.responseBody = respBody + } + res.Body = s.responseBody + return res, nil +} + +type tracingReader struct { + io.Reader + readFirst bool + trace *httptrace.ClientTrace +} + +func (r *tracingReader) Read(b []byte) (int, error) { + n, err := r.Reader.Read(b) + if n > 0 && !r.readFirst { + traceGotFirstResponseByte(r.trace) + r.readFirst = true + } + return n, err +} diff --git a/vendor/github.com/quic-go/quic-go/http3/trace.go b/vendor/github.com/quic-go/quic-go/http3/trace.go index 76de6fb1a9..2bc70017a5 100644 --- a/vendor/github.com/quic-go/quic-go/http3/trace.go +++ b/vendor/github.com/quic-go/quic-go/http3/trace.go @@ -19,7 +19,7 @@ func traceGetConn(trace *httptrace.ClientTrace, hostPort string) { // fakeConn is a wrapper for quic.EarlyConnection // because the quic connection does not implement net.Conn. type fakeConn struct { - conn quic.EarlyConnection + conn *quic.Conn } func (c *fakeConn) Close() error { panic("connection operation prohibited") } @@ -31,7 +31,7 @@ func (c *fakeConn) SetWriteDeadline(t time.Time) error { panic("connection opera func (c *fakeConn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } func (c *fakeConn) LocalAddr() net.Addr { return c.conn.LocalAddr() } -func traceGotConn(trace *httptrace.ClientTrace, conn quic.EarlyConnection, reused bool) { +func traceGotConn(trace *httptrace.ClientTrace, conn *quic.Conn, reused bool) { if trace != nil && trace.GotConn != nil { trace.GotConn(httptrace.GotConnInfo{ Conn: &fakeConn{conn: conn}, diff --git a/vendor/github.com/quic-go/quic-go/http3/transport.go b/vendor/github.com/quic-go/quic-go/http3/transport.go index f1824e594e..dac84bb8da 100644 --- a/vendor/github.com/quic-go/quic-go/http3/transport.go +++ b/vendor/github.com/quic-go/quic-go/http3/transport.go @@ -39,7 +39,7 @@ type RoundTripOpt struct { } type clientConn interface { - OpenRequestStream(context.Context) (RequestStream, error) + OpenRequestStream(context.Context) (*RequestStream, error) RoundTrip(*http.Request) (*http.Response, error) } @@ -47,7 +47,7 @@ type roundTripperWithCount struct { cancel context.CancelFunc dialing chan struct{} // closed as soon as quic.Dial(Early) returned dialErr error - conn quic.EarlyConnection + conn *quic.Conn clientConn clientConn useCount atomic.Int64 @@ -76,7 +76,7 @@ type Transport struct { // connections for requests. // If Dial is nil, a UDPConn will be created at the first request // and will be reused for subsequent connections to other servers. - Dial func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) + Dial func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) // Enable support for HTTP/3 datagrams (RFC 9297). // If a QUICConfig is set, datagram support also needs to be enabled on the QUIC layer by setting EnableDatagrams. @@ -98,8 +98,8 @@ type Transport struct { // However, if the user explicitly requested gzip it is not automatically uncompressed. DisableCompression bool - StreamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error) - UniStreamHijacker func(StreamType, quic.ConnectionTracingID, quic.ReceiveStream, error) (hijacked bool) + StreamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error) + UniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool) Logger *slog.Logger @@ -108,7 +108,7 @@ type Transport struct { initOnce sync.Once initErr error - newClientConn func(quic.EarlyConnection) clientConn + newClientConn func(*quic.Conn) clientConn clients map[string]*roundTripperWithCount transport *quic.Transport @@ -119,15 +119,12 @@ var ( _ io.Closer = &Transport{} ) -// Deprecated: RoundTripper was renamed to Transport. -type RoundTripper = Transport - // ErrNoCachedConn is returned when Transport.OnlyCachedConn is set var ErrNoCachedConn = errors.New("http3: no cached connection was available") func (t *Transport) init() error { if t.newClientConn == nil { - t.newClientConn = func(conn quic.EarlyConnection) clientConn { + t.newClientConn = func(conn *quic.Conn) clientConn { return newClientConn( conn, t.EnableDatagrams, @@ -334,7 +331,7 @@ func (t *Transport) getClient(ctx context.Context, hostname string, onlyCached b return cl, isReused, nil } -func (t *Transport) dial(ctx context.Context, hostname string) (quic.EarlyConnection, clientConn, error) { +func (t *Transport) dial(ctx context.Context, hostname string) (*quic.Conn, clientConn, error) { var tlsConf *tls.Config if t.TLSClientConfig == nil { tlsConf = &tls.Config{} @@ -361,7 +358,7 @@ func (t *Transport) dial(ctx context.Context, hostname string) (quic.EarlyConnec } t.transport = &quic.Transport{Conn: udpConn} } - dial = func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { + dial = func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) { network := "udp" udpAddr, err := t.resolveUDPAddr(ctx, network, addr) if err != nil { @@ -421,7 +418,7 @@ func (t *Transport) removeClient(hostname string) { // // Obtaining a ClientConn is only needed for more advanced use cases, such as // using Extended CONNECT for WebTransport or the various MASQUE protocols. -func (t *Transport) NewClientConn(conn quic.Connection) *ClientConn { +func (t *Transport) NewClientConn(conn *quic.Conn) *ClientConn { return newClientConn( conn, t.EnableDatagrams, diff --git a/vendor/github.com/quic-go/quic-go/interface.go b/vendor/github.com/quic-go/quic-go/interface.go index 99dd9e2e6f..4ba75a378e 100644 --- a/vendor/github.com/quic-go/quic-go/interface.go +++ b/vendor/github.com/quic-go/quic-go/interface.go @@ -4,7 +4,6 @@ import ( "context" "crypto/tls" "errors" - "io" "net" "time" @@ -52,8 +51,8 @@ type TokenStore interface { // when the server rejects a 0-RTT connection attempt. var Err0RTTRejected = errors.New("0-RTT rejected") -// ConnectionTracingKey can be used to associate a [logging.ConnectionTracer] with a [Connection]. -// It is set on the Connection.Context() context, +// ConnectionTracingKey can be used to associate a [logging.ConnectionTracer] with a [Conn]. +// It is set on the Conn.Context() context, // as well as on the context passed to logging.Tracer.NewConnectionTracer. // // Deprecated: Applications can set their own tracing key using Transport.ConnContext. @@ -70,153 +69,6 @@ type connTracingCtxKey struct{} // context returned by tls.Config.ClientInfo.Context. var QUICVersionContextKey = handshake.QUICVersionContextKey -// Stream is the interface implemented by QUIC streams. -// In addition to the errors listed on the [Connection], -// calls to stream functions can return a [StreamError] if the stream is canceled. -type Stream interface { - ReceiveStream - SendStream - // SetDeadline sets the read and write deadlines associated - // with the connection. It is equivalent to calling both - // SetReadDeadline and SetWriteDeadline. - SetDeadline(t time.Time) error -} - -// A ReceiveStream is a unidirectional Receive Stream. -type ReceiveStream interface { - // StreamID returns the stream ID. - StreamID() StreamID - // Read reads data from the stream. - // Read can be made to time out using SetDeadline and SetReadDeadline. - // If the stream was canceled, the error is a StreamError. - io.Reader - // CancelRead aborts receiving on this stream. - // It will ask the peer to stop transmitting stream data. - // Read will unblock immediately, and future Read calls will fail. - // When called multiple times or after reading the io.EOF it is a no-op. - CancelRead(StreamErrorCode) - // SetReadDeadline sets the deadline for future Read calls and - // any currently-blocked Read call. - // A zero value for t means Read will not time out. - SetReadDeadline(t time.Time) error -} - -// A SendStream is a unidirectional Send Stream. -type SendStream interface { - // StreamID returns the stream ID. - StreamID() StreamID - // Write writes data to the stream. - // Write can be made to time out using SetDeadline and SetWriteDeadline. - // If the stream was canceled, the error is a StreamError. - io.Writer - // Close closes the write-direction of the stream. - // Future calls to Write are not permitted after calling Close. - // It must not be called concurrently with Write. - // It must not be called after calling CancelWrite. - io.Closer - // CancelWrite aborts sending on this stream. - // Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably. - // Write will unblock immediately, and future calls to Write will fail. - // When called multiple times it is a no-op. - // When called after Close, it aborts delivery. Note that there is no guarantee if - // the peer will receive the FIN or the reset first. - CancelWrite(StreamErrorCode) - // The Context is canceled as soon as the write-side of the stream is closed. - // This happens when Close() or CancelWrite() is called, or when the peer - // cancels the read-side of their stream. - // The cancellation cause is set to the error that caused the stream to - // close, or `context.Canceled` in case the stream is closed without error. - Context() context.Context - // SetWriteDeadline sets the deadline for future Write calls - // and any currently-blocked Write call. - // Even if write times out, it may return n > 0, indicating that - // some data was successfully written. - // A zero value for t means Write will not time out. - SetWriteDeadline(t time.Time) error -} - -// A Connection is a QUIC connection between two peers. -// Calls to the connection (and to streams) can return the following types of errors: -// - [ApplicationError]: for errors triggered by the application running on top of QUIC -// - [TransportError]: for errors triggered by the QUIC transport (in many cases a misbehaving peer) -// - [IdleTimeoutError]: when the peer goes away unexpectedly (this is a [net.Error] timeout error) -// - [HandshakeTimeoutError]: when the cryptographic handshake takes too long (this is a [net.Error] timeout error) -// - [StatelessResetError]: when we receive a stateless reset -// - [VersionNegotiationError]: returned by the client, when there's no version overlap between the peers -type Connection interface { - // AcceptStream returns the next stream opened by the peer, blocking until one is available. - AcceptStream(context.Context) (Stream, error) - // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. - AcceptUniStream(context.Context) (ReceiveStream, error) - // OpenStream opens a new bidirectional QUIC stream. - // There is no signaling to the peer about new streams: - // The peer can only accept the stream after data has been sent on the stream, - // or the stream has been reset or closed. - // When reaching the peer's stream limit, it is not possible to open a new stream until the - // peer raises the stream limit. In that case, a StreamLimitReachedError is returned. - OpenStream() (Stream, error) - // OpenStreamSync opens a new bidirectional QUIC stream. - // It blocks until a new stream can be opened. - // There is no signaling to the peer about new streams: - // The peer can only accept the stream after data has been sent on the stream, - // or the stream has been reset or closed. - OpenStreamSync(context.Context) (Stream, error) - // OpenUniStream opens a new outgoing unidirectional QUIC stream. - // There is no signaling to the peer about new streams: - // The peer can only accept the stream after data has been sent on the stream, - // or the stream has been reset or closed. - // When reaching the peer's stream limit, it is not possible to open a new stream until the - // peer raises the stream limit. In that case, a StreamLimitReachedError is returned. - OpenUniStream() (SendStream, error) - // OpenUniStreamSync opens a new outgoing unidirectional QUIC stream. - // It blocks until a new stream can be opened. - // There is no signaling to the peer about new streams: - // The peer can only accept the stream after data has been sent on the stream, - // or the stream has been reset or closed. - OpenUniStreamSync(context.Context) (SendStream, error) - // LocalAddr returns the local address. - LocalAddr() net.Addr - // RemoteAddr returns the address of the peer. - RemoteAddr() net.Addr - // CloseWithError closes the connection with an error. - // The error string will be sent to the peer. - CloseWithError(ApplicationErrorCode, string) error - // Context returns a context that is cancelled when the connection is closed. - // The cancellation cause is set to the error that caused the connection to - // close, or `context.Canceled` in case the listener is closed first. - Context() context.Context - // ConnectionState returns basic details about the QUIC connection. - // Warning: This API should not be considered stable and might change soon. - ConnectionState() ConnectionState - - // SendDatagram sends a message using a QUIC datagram, as specified in RFC 9221. - // There is no delivery guarantee for DATAGRAM frames, they are not retransmitted if lost. - // The payload of the datagram needs to fit into a single QUIC packet. - // In addition, a datagram may be dropped before being sent out if the available packet size suddenly decreases. - // If the payload is too large to be sent at the current time, a DatagramTooLargeError is returned. - SendDatagram(payload []byte) error - // ReceiveDatagram gets a message received in a datagram, as specified in RFC 9221. - ReceiveDatagram(context.Context) ([]byte, error) - - AddPath(*Transport) (*Path, error) -} - -// An EarlyConnection is a connection that is handshaking. -// Data sent during the handshake is encrypted using the forward secure keys. -// When using client certificates, the client's identity is only verified -// after completion of the handshake. -type EarlyConnection interface { - Connection - - // HandshakeComplete blocks until the handshake completes (or fails). - // For the client, data sent before completion of the handshake is encrypted with 0-RTT keys. - // For the server, data sent before completion of the handshake is encrypted with 1-RTT keys, - // however the client's identity is only verified once the handshake completes. - HandshakeComplete() <-chan struct{} - - NextConnection(context.Context) (Connection, error) -} - // StatelessResetKey is a key used to derive stateless reset tokens. type StatelessResetKey [32]byte @@ -297,7 +149,7 @@ type Config struct { // limit the memory usage. // To avoid deadlocks, it is not valid to call other functions on the connection or on streams // in this callback. - AllowConnectionWindowIncrease func(conn Connection, delta uint64) bool + AllowConnectionWindowIncrease func(conn *Conn, delta uint64) bool // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open. // If not set, it will default to 100. // If set to a negative value, it doesn't allow any bidirectional streams. @@ -351,7 +203,7 @@ type ConnectionState struct { // TLS contains information about the TLS connection state, incl. the tls.ConnectionState. TLS tls.ConnectionState // SupportsDatagrams indicates whether the peer advertised support for QUIC datagrams (RFC 9221). - // When true, datagrams can be sent using the Connection's SendDatagram method. + // When true, datagrams can be sent using the Conn's SendDatagram method. // This is a unilateral declaration by the peer - receiving datagrams is only possible if // datagram support was enabled locally via Config.EnableDatagrams. SupportsDatagrams bool diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go index 0aca46fe3a..415f85de85 100644 --- a/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go +++ b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go @@ -6,9 +6,7 @@ import ( "crypto/tls" "encoding/binary" "fmt" - "os" - "strconv" - "testing" + "sync/atomic" "time" "github.com/quic-go/quic-go/internal/protocol" @@ -17,14 +15,15 @@ import ( "github.com/quic-go/quic-go/logging" ) -func keyUpdateInterval() uint64 { - // Reparsing the environment variable is not very performant, but it's only done in tests. - if testing.Testing() { - if v, err := strconv.ParseUint(os.Getenv("QUIC_GO_TEST_KEY_UPDATE_INTERVAL"), 10, 64); err == nil { - return v - } - } - return protocol.KeyUpdateInterval +var keyUpdateInterval atomic.Uint64 + +func init() { + keyUpdateInterval.Store(protocol.KeyUpdateInterval) +} + +func SetKeyUpdateInterval(v uint64) (reset func()) { + old := keyUpdateInterval.Swap(v) + return func() { keyUpdateInterval.Store(old) } } // FirstKeyUpdateInterval is the maximum number of packets we send or receive before initiating the first key update. @@ -302,11 +301,11 @@ func (a *updatableAEAD) shouldInitiateKeyUpdate() bool { return true } } - if a.numRcvdWithCurrentKey >= keyUpdateInterval() { + if a.numRcvdWithCurrentKey >= keyUpdateInterval.Load() { a.logger.Debugf("Received %d packets with current key phase. Initiating key update to the next key phase: %d", a.numRcvdWithCurrentKey, a.keyPhase+1) return true } - if a.numSentWithCurrentKey >= keyUpdateInterval() { + if a.numSentWithCurrentKey >= keyUpdateInterval.Load() { a.logger.Debugf("Sent %d packets with current key phase. Initiating key update to the next key phase: %d", a.numSentWithCurrentKey, a.keyPhase+1) return true } diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go b/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go index ad7de864b8..6db4a95b9d 100644 --- a/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go +++ b/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go @@ -1,5 +1,7 @@ package protocol +import "github.com/quic-go/quic-go/quicvarint" + // StreamType encodes if this is a unidirectional or bidirectional stream type StreamType uint8 @@ -23,6 +25,30 @@ const ( // MaxStreamCount is the maximum stream count value that can be sent in MAX_STREAMS frames // and as the stream count in the transport parameters MaxStreamCount StreamNum = 1 << 60 + // MaxStreamID is the maximum stream ID + MaxStreamID StreamID = quicvarint.Max +) + +const ( + // FirstOutgoingBidiStreamClient is the first bidirectional stream opened by the client + FirstOutgoingBidiStreamClient StreamID = 0 + // FirstOutgoingUniStreamClient is the first unidirectional stream opened by the client + FirstOutgoingUniStreamClient StreamID = 2 + // FirstOutgoingBidiStreamServer is the first bidirectional stream opened by the server + FirstOutgoingBidiStreamServer StreamID = 1 + // FirstOutgoingUniStreamServer is the first unidirectional stream opened by the server + FirstOutgoingUniStreamServer StreamID = 3 +) + +const ( + // FirstIncomingBidiStreamServer is the first bidirectional stream accepted by the server + FirstIncomingBidiStreamServer = FirstOutgoingBidiStreamClient + // FirstIncomingUniStreamServer is the first unidirectional stream accepted by the server + FirstIncomingUniStreamServer = FirstOutgoingUniStreamClient + // FirstIncomingBidiStreamClient is the first bidirectional stream accepted by the client + FirstIncomingBidiStreamClient = FirstOutgoingBidiStreamServer + // FirstIncomingUniStreamClient is the first unidirectional stream accepted by the client + FirstIncomingUniStreamClient = FirstOutgoingUniStreamServer ) // StreamID calculates the stream ID. diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/version.go b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go index c9254a045e..8abca5060b 100644 --- a/vendor/github.com/quic-go/quic-go/internal/protocol/version.go +++ b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go @@ -37,7 +37,6 @@ func IsValidVersion(v Version) bool { } func (vn Version) String() string { - //nolint:exhaustive switch vn { case VersionUnknown: return "unknown" diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go b/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go index 1c6ad991db..6ab9fb98ac 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go @@ -61,7 +61,6 @@ func (h *ExtendedHeader) Append(b []byte, v protocol.Version) ([]byte, error) { var packetType uint8 if v == protocol.Version2 { - //nolint:exhaustive switch h.Type { case protocol.PacketTypeInitial: packetType = 0b01 @@ -73,7 +72,6 @@ func (h *ExtendedHeader) Append(b []byte, v protocol.Version) ([]byte, error) { packetType = 0b00 } } else { - //nolint:exhaustive switch h.Type { case protocol.PacketTypeInitial: packetType = 0b00 diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go b/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go index 59d41444a3..794c70ccf1 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go @@ -34,12 +34,16 @@ const ( connectionCloseFrameType = 0x1c applicationCloseFrameType = 0x1d handshakeDoneFrameType = 0x1e + resetStreamAtFrameType = 0x24 // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/ ) +var errUnknownFrameType = errors.New("unknown frame type") + // The FrameParser parses QUIC frames, one by one. type FrameParser struct { - ackDelayExponent uint8 - supportsDatagrams bool + ackDelayExponent uint8 + supportsDatagrams bool + supportsResetStreamAt bool // To avoid allocating when parsing, keep a single ACK frame struct. // It is used over and over again. @@ -47,10 +51,11 @@ type FrameParser struct { } // NewFrameParser creates a new frame parser. -func NewFrameParser(supportsDatagrams bool) *FrameParser { +func NewFrameParser(supportsDatagrams, supportsResetStreamAt bool) *FrameParser { return &FrameParser{ - supportsDatagrams: supportsDatagrams, - ackFrame: &AckFrame{}, + supportsDatagrams: supportsDatagrams, + supportsResetStreamAt: supportsResetStreamAt, + ackFrame: &AckFrame{}, } } @@ -110,7 +115,7 @@ func (p *FrameParser) parseFrame(b []byte, typ uint64, encLevel protocol.Encrypt l, err = parseAckFrame(p.ackFrame, b, typ, ackDelayExponent, v) frame = p.ackFrame case resetStreamFrameType: - frame, l, err = parseResetStreamFrame(b, v) + frame, l, err = parseResetStreamFrame(b, false, v) case stopSendingFrameType: frame, l, err = parseStopSendingFrame(b, v) case cryptoFrameType: @@ -142,13 +147,17 @@ func (p *FrameParser) parseFrame(b []byte, typ uint64, encLevel protocol.Encrypt case handshakeDoneFrameType: frame = &HandshakeDoneFrame{} case 0x30, 0x31: - if p.supportsDatagrams { - frame, l, err = parseDatagramFrame(b, typ, v) - break + if !p.supportsDatagrams { + return nil, 0, errUnknownFrameType + } + frame, l, err = parseDatagramFrame(b, typ, v) + case resetStreamAtFrameType: + if !p.supportsResetStreamAt { + return nil, 0, errUnknownFrameType } - fallthrough + frame, l, err = parseResetStreamFrame(b, true, v) default: - err = errors.New("unknown frame type") + err = errUnknownFrameType } } if err != nil { diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go index a20029af26..cb678bf453 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go @@ -1,55 +1,79 @@ package wire import ( + "fmt" + "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/quicvarint" ) -// A ResetStreamFrame is a RESET_STREAM frame in QUIC +// A ResetStreamFrame is a RESET_STREAM or RESET_STREAM_AT frame in QUIC type ResetStreamFrame struct { - StreamID protocol.StreamID - ErrorCode qerr.StreamErrorCode - FinalSize protocol.ByteCount + StreamID protocol.StreamID + ErrorCode qerr.StreamErrorCode + FinalSize protocol.ByteCount + ReliableSize protocol.ByteCount } -func parseResetStreamFrame(b []byte, _ protocol.Version) (*ResetStreamFrame, int, error) { +func parseResetStreamFrame(b []byte, isResetStreamAt bool, _ protocol.Version) (*ResetStreamFrame, int, error) { startLen := len(b) - var streamID protocol.StreamID - var byteOffset protocol.ByteCount - sid, l, err := quicvarint.Parse(b) + streamID, l, err := quicvarint.Parse(b) if err != nil { return nil, 0, replaceUnexpectedEOF(err) } b = b[l:] - streamID = protocol.StreamID(sid) errorCode, l, err := quicvarint.Parse(b) if err != nil { return nil, 0, replaceUnexpectedEOF(err) } b = b[l:] - bo, l, err := quicvarint.Parse(b) + finalSize, l, err := quicvarint.Parse(b) if err != nil { return nil, 0, replaceUnexpectedEOF(err) } - byteOffset = protocol.ByteCount(bo) + b = b[l:] + + var reliableSize uint64 + if isResetStreamAt { + reliableSize, l, err = quicvarint.Parse(b) + if err != nil { + return nil, 0, replaceUnexpectedEOF(err) + } + b = b[l:] + } + if reliableSize > finalSize { + return nil, 0, fmt.Errorf("RESET_STREAM_AT: reliable size can't be larger than final size (%d vs %d)", reliableSize, finalSize) + } return &ResetStreamFrame{ - StreamID: streamID, - ErrorCode: qerr.StreamErrorCode(errorCode), - FinalSize: byteOffset, - }, startLen - len(b) + l, nil + StreamID: protocol.StreamID(streamID), + ErrorCode: qerr.StreamErrorCode(errorCode), + FinalSize: protocol.ByteCount(finalSize), + ReliableSize: protocol.ByteCount(reliableSize), + }, startLen - len(b), nil } func (f *ResetStreamFrame) Append(b []byte, _ protocol.Version) ([]byte, error) { - b = append(b, resetStreamFrameType) + if f.ReliableSize == 0 { + b = quicvarint.Append(b, resetStreamFrameType) + } else { + b = quicvarint.Append(b, resetStreamAtFrameType) + } b = quicvarint.Append(b, uint64(f.StreamID)) b = quicvarint.Append(b, uint64(f.ErrorCode)) b = quicvarint.Append(b, uint64(f.FinalSize)) + if f.ReliableSize > 0 { + b = quicvarint.Append(b, uint64(f.ReliableSize)) + } return b, nil } // Length of a written frame func (f *ResetStreamFrame) Length(protocol.Version) protocol.ByteCount { - return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID))+quicvarint.Len(uint64(f.ErrorCode))+quicvarint.Len(uint64(f.FinalSize))) + size := 1 // the frame type for both RESET_STREAM and RESET_STREAM_AT fits into 1 byte + if f.ReliableSize > 0 { + size += quicvarint.Len(uint64(f.ReliableSize)) + } + return protocol.ByteCount(size + quicvarint.Len(uint64(f.StreamID)) + quicvarint.Len(uint64(f.ErrorCode)) + quicvarint.Len(uint64(f.FinalSize))) } diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go index d39189a0d5..2437892a0d 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go @@ -45,6 +45,8 @@ const ( retrySourceConnectionIDParameterID transportParameterID = 0x10 // RFC 9221 maxDatagramFrameSizeParameterID transportParameterID = 0x20 + // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/ + resetStreamAtParameterID transportParameterID = 0x17f7586d2cb571 ) // PreferredAddress is the value encoding in the preferred_address transport parameter @@ -82,7 +84,8 @@ type TransportParameters struct { StatelessResetToken *protocol.StatelessResetToken ActiveConnectionIDLimit uint64 - MaxDatagramFrameSize protocol.ByteCount + MaxDatagramFrameSize protocol.ByteCount // RFC 9221 + EnableResetStreamAt bool // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/ } // Unmarshal the transport parameters @@ -199,6 +202,11 @@ func (p *TransportParameters) unmarshal(b []byte, sentBy protocol.Perspective, f connID := protocol.ParseConnectionID(b[:paramLen]) b = b[paramLen:] p.RetrySourceConnectionID = &connID + case resetStreamAtParameterID: + if paramLen != 0 { + return fmt.Errorf("wrong length for reset_stream_at: %d (expected empty)", paramLen) + } + p.EnableResetStreamAt = true default: b = b[paramLen:] } @@ -428,9 +436,15 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte { b = quicvarint.Append(b, uint64(p.RetrySourceConnectionID.Len())) b = append(b, p.RetrySourceConnectionID.Bytes()...) } + // QUIC datagrams if p.MaxDatagramFrameSize != protocol.InvalidByteCount { b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize)) } + // QUIC Stream Resets with Partial Delivery + if p.EnableResetStreamAt { + b = quicvarint.Append(b, uint64(resetStreamAtParameterID)) + b = quicvarint.Append(b, 0) + } if pers == protocol.PerspectiveClient && len(AdditionalTransportParametersClient) > 0 { for k, v := range AdditionalTransportParametersClient { @@ -472,12 +486,18 @@ func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte { b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum)) // initial_max_uni_streams b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum)) + // active_connection_id_limit + b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) // max_datagram_frame_size if p.MaxDatagramFrameSize != protocol.InvalidByteCount { b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize)) } - // active_connection_id_limit - return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) + // reset_stream_at + if p.EnableResetStreamAt { + b = quicvarint.Append(b, uint64(resetStreamAtParameterID)) + b = quicvarint.Append(b, 0) + } + return b } // UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket. @@ -524,13 +544,13 @@ func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool { // String returns a string representation, intended for logging. func (p *TransportParameters) String() string { logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, " - logParams := []interface{}{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID} + logParams := []any{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID} if p.RetrySourceConnectionID != nil { logString += "RetrySourceConnectionID: %s, " logParams = append(logParams, p.RetrySourceConnectionID) } logString += "InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d" - logParams = append(logParams, []interface{}{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...) + logParams = append(logParams, []any{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...) if p.StatelessResetToken != nil { // the client never sends a stateless reset token logString += ", StatelessResetToken: %#x" logParams = append(logParams, *p.StatelessResetToken) @@ -539,6 +559,8 @@ func (p *TransportParameters) String() string { logString += ", MaxDatagramFrameSize: %d" logParams = append(logParams, p.MaxDatagramFrameSize) } + logString += ", EnableResetStreamAt: %t" + logParams = append(logParams, p.EnableResetStreamAt) logString += "}" return fmt.Sprintf(logString, logParams...) } diff --git a/vendor/github.com/quic-go/quic-go/mockgen.go b/vendor/github.com/quic-go/quic-go/mockgen.go index f46c204989..9e1f62f2ee 100644 --- a/vendor/github.com/quic-go/quic-go/mockgen.go +++ b/vendor/github.com/quic-go/quic-go/mockgen.go @@ -11,30 +11,21 @@ type RawConn = rawConn //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender" type Sender = sender -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI" -type StreamI = streamI - -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI" -type ReceiveStreamI = receiveStreamI - -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI" -type SendStreamI = sendStreamI - //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender" type StreamSender = streamSender //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_control_frame_getter_test.go github.com/quic-go/quic-go StreamControlFrameGetter" type StreamControlFrameGetter = streamControlFrameGetter +//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_frame_getter_test.go github.com/quic-go/quic-go StreamFrameGetter" +type StreamFrameGetter = streamFrameGetter + //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource" type FrameSource = frameSource //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource" type AckFrameSource = ackFrameSource -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager" -type StreamManager = streamManager - //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager" type SealingManager = sealingManager @@ -50,9 +41,6 @@ type MTUDiscoverer = mtuDiscoverer //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner" type ConnRunner = connRunner -//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn" -type QUICConn = quicConn - //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler" type PacketHandler = packetHandler diff --git a/vendor/github.com/quic-go/quic-go/quicvarint/varint.go b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go index f095e29897..0a19eaafe9 100644 --- a/vendor/github.com/quic-go/quic-go/quicvarint/varint.go +++ b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go @@ -1,6 +1,7 @@ package quicvarint import ( + "encoding/binary" "fmt" "io" ) @@ -74,23 +75,30 @@ func Parse(b []byte) (uint64 /* value */, int /* bytes consumed */, error) { if len(b) == 0 { return 0, 0, io.EOF } - firstByte := b[0] - // the first two bits of the first byte encode the length - l := 1 << ((firstByte & 0xc0) >> 6) - if len(b) < l { - return 0, 0, io.ErrUnexpectedEOF - } - b0 := firstByte & (0xff - 0xc0) - if l == 1 { - return uint64(b0), 1, nil - } - if l == 2 { - return uint64(b[1]) + uint64(b0)<<8, 2, nil - } - if l == 4 { - return uint64(b[3]) + uint64(b[2])<<8 + uint64(b[1])<<16 + uint64(b0)<<24, 4, nil + + first := b[0] + switch first >> 6 { + case 0: // 1-byte encoding: 00xxxxxx + return uint64(first & 0b00111111), 1, nil + case 1: // 2-byte encoding: 01xxxxxx + if len(b) < 2 { + return 0, 0, io.ErrUnexpectedEOF + } + return uint64(b[1]) | uint64(first&0b00111111)<<8, 2, nil + case 2: // 4-byte encoding: 10xxxxxx + if len(b) < 4 { + return 0, 0, io.ErrUnexpectedEOF + } + return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(first&0b00111111)<<24, 4, nil + case 3: // 8-byte encoding: 00xxxxxx + if len(b) < 8 { + return 0, 0, io.ErrUnexpectedEOF + } + // binary.BigEndian.Uint64 only reads the first 8 bytes. Passing the full slice avoids slicing overhead. + return binary.BigEndian.Uint64(b) & 0x3fffffffffffffff, 8, nil } - return uint64(b[7]) + uint64(b[6])<<8 + uint64(b[5])<<16 + uint64(b[4])<<24 + uint64(b[3])<<32 + uint64(b[2])<<40 + uint64(b[1])<<48 + uint64(b0)<<56, 8, nil + + panic("unreachable") } // Append appends i in the QUIC varint format. diff --git a/vendor/github.com/quic-go/quic-go/receive_stream.go b/vendor/github.com/quic-go/quic-go/receive_stream.go index 192b92f7cb..3b2d618ce5 100644 --- a/vendor/github.com/quic-go/quic-go/receive_stream.go +++ b/vendor/github.com/quic-go/quic-go/receive_stream.go @@ -14,15 +14,8 @@ import ( "github.com/quic-go/quic-go/internal/wire" ) -type receiveStreamI interface { - ReceiveStream - - handleStreamFrame(*wire.StreamFrame, time.Time) error - handleResetStreamFrame(*wire.ResetStreamFrame, time.Time) error - closeForShutdown(error) -} - -type receiveStream struct { +// A ReceiveStream is a unidirectional Receive Stream. +type ReceiveStream struct { mutex sync.Mutex streamID protocol.StreamID @@ -57,17 +50,16 @@ type receiveStream struct { } var ( - _ ReceiveStream = &receiveStream{} - _ receiveStreamI = &receiveStream{} - _ streamControlFrameGetter = &receiveStream{} + _ streamControlFrameGetter = &ReceiveStream{} + _ receiveStreamFrameHandler = &ReceiveStream{} ) func newReceiveStream( streamID protocol.StreamID, sender streamSender, flowController flowcontrol.StreamFlowController, -) *receiveStream { - return &receiveStream{ +) *ReceiveStream { + return &ReceiveStream{ streamID: streamID, sender: sender, flowController: flowController, @@ -78,12 +70,15 @@ func newReceiveStream( } } -func (s *receiveStream) StreamID() protocol.StreamID { +// StreamID returns the stream ID. +func (s *ReceiveStream) StreamID() protocol.StreamID { return s.streamID } -// Read implements io.Reader. It is not thread safe! -func (s *receiveStream) Read(p []byte) (int, error) { +// Read reads data from the stream. +// Read can be made to time out using [ReceiveStream.SetReadDeadline]. +// If the stream was canceled, the error is a [StreamError]. +func (s *ReceiveStream) Read(p []byte) (int, error) { // Concurrent use of Read is not permitted (and doesn't make any sense), // but sometimes people do it anyway. // Make sure that we only execute one call at any given time to avoid hard to debug failures. @@ -107,7 +102,7 @@ func (s *receiveStream) Read(p []byte) (int, error) { return n, err } -func (s *receiveStream) isNewlyCompleted() bool { +func (s *ReceiveStream) isNewlyCompleted() bool { if s.completed { return false } @@ -128,7 +123,7 @@ func (s *receiveStream) isNewlyCompleted() bool { return false } -func (s *receiveStream) readImpl(p []byte) (hasStreamWindowUpdate bool, hasConnWindowUpdate bool, _ int, _ error) { +func (s *ReceiveStream) readImpl(p []byte) (hasStreamWindowUpdate bool, hasConnWindowUpdate bool, _ int, _ error) { if s.currentFrameIsLast && s.currentFrame == nil { s.errorRead = true return false, false, 0, io.EOF @@ -229,7 +224,7 @@ func (s *receiveStream) readImpl(p []byte) (hasStreamWindowUpdate bool, hasConnW return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, nil } -func (s *receiveStream) dequeueNextFrame() { +func (s *ReceiveStream) dequeueNextFrame() { var offset protocol.ByteCount // We're done with the last frame. Release the buffer. if s.currentFrameDone != nil { @@ -240,7 +235,11 @@ func (s *receiveStream) dequeueNextFrame() { s.readPosInFrame = 0 } -func (s *receiveStream) CancelRead(errorCode StreamErrorCode) { +// CancelRead aborts receiving on this stream. +// It instructs the peer to stop transmitting stream data. +// Read will unblock immediately, and future Read calls will fail. +// When called multiple times or after reading the io.EOF it is a no-op. +func (s *ReceiveStream) CancelRead(errorCode StreamErrorCode) { s.mutex.Lock() queuedNewControlFrame := s.cancelReadImpl(errorCode) completed := s.isNewlyCompleted() @@ -255,7 +254,7 @@ func (s *receiveStream) CancelRead(errorCode StreamErrorCode) { } } -func (s *receiveStream) cancelReadImpl(errorCode qerr.StreamErrorCode) (queuedNewControlFrame bool) { +func (s *ReceiveStream) cancelReadImpl(errorCode qerr.StreamErrorCode) (queuedNewControlFrame bool) { if s.cancelledLocally { // duplicate call to CancelRead return false } @@ -272,7 +271,7 @@ func (s *receiveStream) cancelReadImpl(errorCode qerr.StreamErrorCode) (queuedNe return true } -func (s *receiveStream) handleStreamFrame(frame *wire.StreamFrame, now time.Time) error { +func (s *ReceiveStream) handleStreamFrame(frame *wire.StreamFrame, now time.Time) error { s.mutex.Lock() err := s.handleStreamFrameImpl(frame, now) completed := s.isNewlyCompleted() @@ -285,7 +284,7 @@ func (s *receiveStream) handleStreamFrame(frame *wire.StreamFrame, now time.Time return err } -func (s *receiveStream) handleStreamFrameImpl(frame *wire.StreamFrame, now time.Time) error { +func (s *ReceiveStream) handleStreamFrameImpl(frame *wire.StreamFrame, now time.Time) error { maxOffset := frame.Offset + frame.DataLen() if err := s.flowController.UpdateHighestReceived(maxOffset, frame.Fin, now); err != nil { return err @@ -303,7 +302,7 @@ func (s *receiveStream) handleStreamFrameImpl(frame *wire.StreamFrame, now time. return nil } -func (s *receiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame, now time.Time) error { +func (s *ReceiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame, now time.Time) error { s.mutex.Lock() err := s.handleResetStreamFrameImpl(frame, now) completed := s.isNewlyCompleted() @@ -315,7 +314,7 @@ func (s *receiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame, now return err } -func (s *receiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame, now time.Time) error { +func (s *ReceiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame, now time.Time) error { if s.closeForShutdownErr != nil { return nil } @@ -339,7 +338,7 @@ func (s *receiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame, return nil } -func (s *receiveStream) getControlFrame(now time.Time) (_ ackhandler.Frame, ok, hasMore bool) { +func (s *ReceiveStream) getControlFrame(now time.Time) (_ ackhandler.Frame, ok, hasMore bool) { s.mutex.Lock() defer s.mutex.Unlock() @@ -362,7 +361,10 @@ func (s *receiveStream) getControlFrame(now time.Time) (_ ackhandler.Frame, ok, }, true, false } -func (s *receiveStream) SetReadDeadline(t time.Time) error { +// SetReadDeadline sets the deadline for future Read calls and +// any currently-blocked Read call. +// A zero value for t means Read will not time out. +func (s *ReceiveStream) SetReadDeadline(t time.Time) error { s.mutex.Lock() s.deadline = t s.mutex.Unlock() @@ -373,7 +375,7 @@ func (s *receiveStream) SetReadDeadline(t time.Time) error { // CloseForShutdown closes a stream abruptly. // It makes Read unblock (and return the error) immediately. // The peer will NOT be informed about this: the stream is closed without sending a FIN or RESET. -func (s *receiveStream) closeForShutdown(err error) { +func (s *ReceiveStream) closeForShutdown(err error) { s.mutex.Lock() s.closeForShutdownErr = err s.mutex.Unlock() @@ -381,7 +383,7 @@ func (s *receiveStream) closeForShutdown(err error) { } // signalRead performs a non-blocking send on the readChan -func (s *receiveStream) signalRead() { +func (s *ReceiveStream) signalRead() { select { case s.readChan <- struct{}{}: default: diff --git a/vendor/github.com/quic-go/quic-go/send_stream.go b/vendor/github.com/quic-go/quic-go/send_stream.go index a588cc8ad6..0c76ee5e31 100644 --- a/vendor/github.com/quic-go/quic-go/send_stream.go +++ b/vendor/github.com/quic-go/quic-go/send_stream.go @@ -14,16 +14,8 @@ import ( "github.com/quic-go/quic-go/internal/wire" ) -type sendStreamI interface { - SendStream - handleStopSendingFrame(*wire.StopSendingFrame) - hasData() bool - popStreamFrame(protocol.ByteCount, protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) - closeForShutdown(error) - updateSendWindow(protocol.ByteCount) -} - -type sendStream struct { +// A SendStream is a unidirectional Send Stream. +type SendStream struct { mutex sync.Mutex numOutstandingFrames int64 // outstanding STREAM and RESET_STREAM frames @@ -63,9 +55,9 @@ type sendStream struct { } var ( - _ SendStream = &sendStream{} - _ sendStreamI = &sendStream{} - _ streamControlFrameGetter = &sendStream{} + _ streamControlFrameGetter = &SendStream{} + _ outgoingStream = &SendStream{} + _ sendStreamFrameHandler = &SendStream{} ) func newSendStream( @@ -73,8 +65,8 @@ func newSendStream( streamID protocol.StreamID, sender streamSender, flowController flowcontrol.StreamFlowController, -) *sendStream { - s := &sendStream{ +) *SendStream { + s := &SendStream{ streamID: streamID, sender: sender, flowController: flowController, @@ -85,11 +77,15 @@ func newSendStream( return s } -func (s *sendStream) StreamID() protocol.StreamID { +// StreamID returns the stream ID. +func (s *SendStream) StreamID() StreamID { return s.streamID // same for receiveStream and sendStream } -func (s *sendStream) Write(p []byte) (int, error) { +// Write writes data to the stream. +// Write can be made to time out using [SendStream.SetWriteDeadline]. +// If the stream was canceled, the error is a [StreamError]. +func (s *SendStream) Write(p []byte) (int, error) { // Concurrent use of Write is not permitted (and doesn't make any sense), // but sometimes people do it anyway. // Make sure that we only execute one call at any given time to avoid hard to debug failures. @@ -103,7 +99,7 @@ func (s *sendStream) Write(p []byte) (int, error) { return n, err } -func (s *sendStream) write(p []byte) (bool /* is newly completed */, int, error) { +func (s *SendStream) write(p []byte) (bool /* is newly completed */, int, error) { s.mutex.Lock() defer s.mutex.Unlock() @@ -207,7 +203,7 @@ func (s *sendStream) write(p []byte) (bool /* is newly completed */, int, error) return false, bytesWritten, nil } -func (s *sendStream) canBufferStreamFrame() bool { +func (s *SendStream) canBufferStreamFrame() bool { var l protocol.ByteCount if s.nextFrame != nil { l = s.nextFrame.DataLen() @@ -217,7 +213,7 @@ func (s *sendStream) canBufferStreamFrame() bool { // popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream // maxBytes is the maximum length this frame (including frame header) will have. -func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) { +func (s *SendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) { s.mutex.Lock() f, blocked, hasMoreData := s.popNewOrRetransmittedStreamFrame(maxBytes, v) if f != nil { @@ -234,7 +230,7 @@ func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Vers }, blocked, hasMoreData } -func (s *sendStream) popNewOrRetransmittedStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ *wire.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMoreData bool) { +func (s *SendStream) popNewOrRetransmittedStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ *wire.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMoreData bool) { if s.finalError != nil { return nil, nil, false } @@ -290,7 +286,7 @@ func (s *sendStream) popNewOrRetransmittedStreamFrame(maxBytes protocol.ByteCoun return f, blocked, hasMoreData } -func (s *sendStream) popNewStreamFrame(maxBytes, sendWindow protocol.ByteCount, v protocol.Version) (*wire.StreamFrame, bool) { +func (s *SendStream) popNewStreamFrame(maxBytes, sendWindow protocol.ByteCount, v protocol.Version) (*wire.StreamFrame, bool) { if s.nextFrame != nil { maxDataLen := min(sendWindow, s.nextFrame.MaxDataLen(maxBytes, v)) if maxDataLen == 0 { @@ -327,7 +323,7 @@ func (s *sendStream) popNewStreamFrame(maxBytes, sendWindow protocol.ByteCount, return f, hasMoreData } -func (s *sendStream) popNewStreamFrameWithoutBuffer(f *wire.StreamFrame, maxBytes, sendWindow protocol.ByteCount, v protocol.Version) bool { +func (s *SendStream) popNewStreamFrameWithoutBuffer(f *wire.StreamFrame, maxBytes, sendWindow protocol.ByteCount, v protocol.Version) bool { maxDataLen := f.MaxDataLen(maxBytes, v) if maxDataLen == 0 { // a STREAM frame must have at least one byte of data return s.dataForWriting != nil || s.nextFrame != nil || s.finishedWriting @@ -337,7 +333,7 @@ func (s *sendStream) popNewStreamFrameWithoutBuffer(f *wire.StreamFrame, maxByte return s.dataForWriting != nil || s.nextFrame != nil || s.finishedWriting } -func (s *sendStream) maybeGetRetransmission(maxBytes protocol.ByteCount, v protocol.Version) (*wire.StreamFrame, bool /* has more retransmissions */) { +func (s *SendStream) maybeGetRetransmission(maxBytes protocol.ByteCount, v protocol.Version) (*wire.StreamFrame, bool /* has more retransmissions */) { f := s.retransmissionQueue[0] newFrame, needsSplit := f.MaybeSplitOffFrame(maxBytes, v) if needsSplit { @@ -347,14 +343,7 @@ func (s *sendStream) maybeGetRetransmission(maxBytes protocol.ByteCount, v proto return f, len(s.retransmissionQueue) > 0 } -func (s *sendStream) hasData() bool { - s.mutex.Lock() - hasData := len(s.dataForWriting) > 0 - s.mutex.Unlock() - return hasData -} - -func (s *sendStream) getDataForWriting(f *wire.StreamFrame, maxBytes protocol.ByteCount) { +func (s *SendStream) getDataForWriting(f *wire.StreamFrame, maxBytes protocol.ByteCount) { if protocol.ByteCount(len(s.dataForWriting)) <= maxBytes { f.Data = f.Data[:len(s.dataForWriting)] copy(f.Data, s.dataForWriting) @@ -370,7 +359,7 @@ func (s *sendStream) getDataForWriting(f *wire.StreamFrame, maxBytes protocol.By } } -func (s *sendStream) isNewlyCompleted() bool { +func (s *SendStream) isNewlyCompleted() bool { if s.completed { return false } @@ -395,7 +384,11 @@ func (s *sendStream) isNewlyCompleted() bool { return false } -func (s *sendStream) Close() error { +// Close closes the write-direction of the stream. +// Future calls to Write are not permitted after calling Close. +// It must not be called concurrently with Write. +// It must not be called after calling CancelWrite. +func (s *SendStream) Close() error { s.mutex.Lock() if s.closedForShutdown || s.finishedWriting { s.mutex.Unlock() @@ -421,14 +414,20 @@ func (s *sendStream) Close() error { return nil } -func (s *sendStream) CancelWrite(errorCode StreamErrorCode) { +// CancelWrite aborts sending on this stream. +// Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably. +// Write will unblock immediately, and future calls to Write will fail. +// When called multiple times it is a no-op. +// When called after Close, it aborts reliable delivery of outstanding stream data. +// Note that there is no guarantee if the peer will receive the FIN or the cancellation error first. +func (s *SendStream) CancelWrite(errorCode StreamErrorCode) { s.cancelWrite(errorCode, false) } // cancelWrite cancels the stream // It is possible to cancel a stream after it has been closed, both locally and remotely. // This is useful to prevent the retransmission of outstanding stream data. -func (s *sendStream) cancelWrite(errorCode qerr.StreamErrorCode, remote bool) { +func (s *SendStream) cancelWrite(errorCode qerr.StreamErrorCode, remote bool) { s.mutex.Lock() if s.closedForShutdown { s.mutex.Unlock() @@ -468,7 +467,7 @@ func (s *sendStream) cancelWrite(errorCode qerr.StreamErrorCode, remote bool) { s.sender.onHasStreamControlFrame(s.streamID, s) } -func (s *sendStream) updateSendWindow(limit protocol.ByteCount) { +func (s *SendStream) updateSendWindow(limit protocol.ByteCount) { updated := s.flowController.UpdateSendWindow(limit) if !updated { // duplicate or reordered MAX_STREAM_DATA frame return @@ -481,11 +480,11 @@ func (s *sendStream) updateSendWindow(limit protocol.ByteCount) { } } -func (s *sendStream) handleStopSendingFrame(frame *wire.StopSendingFrame) { +func (s *SendStream) handleStopSendingFrame(frame *wire.StopSendingFrame) { s.cancelWrite(frame.ErrorCode, true) } -func (s *sendStream) getControlFrame(time.Time) (_ ackhandler.Frame, ok, hasMore bool) { +func (s *SendStream) getControlFrame(time.Time) (_ ackhandler.Frame, ok, hasMore bool) { s.mutex.Lock() defer s.mutex.Unlock() @@ -501,11 +500,21 @@ func (s *sendStream) getControlFrame(time.Time) (_ ackhandler.Frame, ok, hasMore return f, true, false } -func (s *sendStream) Context() context.Context { +// The Context is canceled as soon as the write-side of the stream is closed. +// This happens when Close() or CancelWrite() is called, or when the peer +// cancels the read-side of their stream. +// The cancellation cause is set to the error that caused the stream to +// close, or `context.Canceled` in case the stream is closed without error. +func (s *SendStream) Context() context.Context { return s.ctx } -func (s *sendStream) SetWriteDeadline(t time.Time) error { +// SetWriteDeadline sets the deadline for future Write calls +// and any currently-blocked Write call. +// Even if write times out, it may return n > 0, indicating that +// some data was successfully written. +// A zero value for t means Write will not time out. +func (s *SendStream) SetWriteDeadline(t time.Time) error { s.mutex.Lock() s.deadline = t s.mutex.Unlock() @@ -516,7 +525,7 @@ func (s *sendStream) SetWriteDeadline(t time.Time) error { // CloseForShutdown closes a stream abruptly. // It makes Write unblock (and return the error) immediately. // The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. -func (s *sendStream) closeForShutdown(err error) { +func (s *SendStream) closeForShutdown(err error) { s.mutex.Lock() s.closedForShutdown = true if s.finalError == nil && !s.finishedWriting { @@ -527,14 +536,14 @@ func (s *sendStream) closeForShutdown(err error) { } // signalWrite performs a non-blocking send on the writeChan -func (s *sendStream) signalWrite() { +func (s *SendStream) signalWrite() { select { case s.writeChan <- struct{}{}: default: } } -type sendStreamAckHandler sendStream +type sendStreamAckHandler SendStream var _ ackhandler.FrameHandler = &sendStreamAckHandler{} @@ -550,7 +559,7 @@ func (s *sendStreamAckHandler) OnAcked(f wire.Frame) { if s.numOutstandingFrames < 0 { panic("numOutStandingFrames negative") } - completed := (*sendStream)(s).isNewlyCompleted() + completed := (*SendStream)(s).isNewlyCompleted() s.mutex.Unlock() if completed { @@ -573,10 +582,10 @@ func (s *sendStreamAckHandler) OnLost(f wire.Frame) { } s.mutex.Unlock() - s.sender.onHasStreamData(s.streamID, (*sendStream)(s)) + s.sender.onHasStreamData(s.streamID, (*SendStream)(s)) } -type sendStreamResetStreamHandler sendStream +type sendStreamResetStreamHandler SendStream var _ ackhandler.FrameHandler = &sendStreamResetStreamHandler{} @@ -586,7 +595,7 @@ func (s *sendStreamResetStreamHandler) OnAcked(wire.Frame) { if s.numOutstandingFrames < 0 { panic("numOutStandingFrames negative") } - completed := (*sendStream)(s).isNewlyCompleted() + completed := (*SendStream)(s).isNewlyCompleted() s.mutex.Unlock() if completed { @@ -599,5 +608,5 @@ func (s *sendStreamResetStreamHandler) OnLost(f wire.Frame) { s.queuedResetStreamFrame = f.(*wire.ResetStreamFrame) s.numOutstandingFrames-- s.mutex.Unlock() - s.sender.onHasStreamControlFrame(s.streamID, (*sendStream)(s)) + s.sender.onHasStreamControlFrame(s.streamID, (*SendStream)(s)) } diff --git a/vendor/github.com/quic-go/quic-go/server.go b/vendor/github.com/quic-go/quic-go/server.go index 3ea2adff3a..f6bef2d8d2 100644 --- a/vendor/github.com/quic-go/quic-go/server.go +++ b/vendor/github.com/quic-go/quic-go/server.go @@ -32,15 +32,6 @@ type packetHandler interface { closeWithTransportError(qerr.TransportErrorCode) } -type quicConn interface { - EarlyConnection - earlyConnReady() <-chan struct{} - handlePacket(receivedPacket) - run() error - destroy(error) - closeWithTransportError(TransportErrorCode) -} - type zeroRTTQueue struct { packets []receivedPacket expiration time.Time @@ -97,7 +88,7 @@ type baseServer struct { *logging.ConnectionTracer, utils.Logger, protocol.Version, - ) quicConn + ) *wrappedConn closeMx sync.Mutex // errorChan is closed when Close is called. This has two effects: @@ -120,7 +111,7 @@ type baseServer struct { verifySourceAddress func(net.Addr) bool - connQueue chan quicConn + connQueue chan *Conn tracer *logging.Tracer @@ -134,7 +125,7 @@ type Listener struct { } // Accept returns new connections. It should be called in a loop. -func (l *Listener) Accept(ctx context.Context) (Connection, error) { +func (l *Listener) Accept(ctx context.Context) (*Conn, error) { return l.baseServer.Accept(ctx) } @@ -162,8 +153,12 @@ type EarlyListener struct { } // Accept returns a new connections. It should be called in a loop. -func (l *EarlyListener) Accept(ctx context.Context) (EarlyConnection, error) { - return l.baseServer.accept(ctx) +func (l *EarlyListener) Accept(ctx context.Context) (*Conn, error) { + conn, err := l.baseServer.accept(ctx) + if err != nil { + return nil, err + } + return conn, nil } // Close the server. All active connections will be closed. @@ -263,7 +258,7 @@ func newServer( verifySourceAddress: verifySourceAddress, connIDGenerator: connIDGenerator, statelessResetter: statelessResetter, - connQueue: make(chan quicConn, protocol.MaxAcceptQueueSize), + connQueue: make(chan *Conn, protocol.MaxAcceptQueueSize), errorChan: make(chan struct{}), stopAccepting: make(chan struct{}), running: make(chan struct{}), @@ -326,11 +321,11 @@ func (s *baseServer) runSendQueue() { // Accept returns connections that already completed the handshake. // It is only valid if acceptEarlyConns is false. -func (s *baseServer) Accept(ctx context.Context) (Connection, error) { +func (s *baseServer) Accept(ctx context.Context) (*Conn, error) { return s.accept(ctx) } -func (s *baseServer) accept(ctx context.Context) (quicConn, error) { +func (s *baseServer) accept(ctx context.Context) (*Conn, error) { select { case <-ctx.Done(): return nil, ctx.Err() @@ -348,11 +343,13 @@ func (s *baseServer) accept(ctx context.Context) (quicConn, error) { } func (s *baseServer) Close() error { - s.close(ErrServerClosed, true) + s.close(ErrServerClosed, false) return nil } -func (s *baseServer) close(e error, notifyOnClose bool) { +// close closes the server. The Transport mutex must not be held while calling this method. +// This method closes any handshaking connections which requires the tranpsort mutex. +func (s *baseServer) close(e error, transportClose bool) { s.closeMx.Lock() if s.closeErr != nil { s.closeMx.Unlock() @@ -363,12 +360,25 @@ func (s *baseServer) close(e error, notifyOnClose bool) { <-s.running s.closeMx.Unlock() - if notifyOnClose { + if !transportClose { s.onClose() } + // wait until all handshakes in flight have terminated s.handshakingCount.Wait() close(s.stopAccepting) + + if transportClose { + // if the transport is closing, drain the connQueue. All connections in the queue + // will be closed by the transport. + for { + select { + case <-s.connQueue: + default: + return + } + } + } } // Addr returns the server's network address @@ -659,7 +669,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error config = populateConfig(conf) } - var conn quicConn + var conn *wrappedConn var cancel context.CancelCauseFunc ctx, cancel1 := context.WithCancelCause(context.Background()) if s.connContext != nil { @@ -759,7 +769,7 @@ func (s *baseServer) refuseNewConn(p receivedPacket, hdr *wire.Header) { } } -func (s *baseServer) handleNewConn(conn quicConn) { +func (s *baseServer) handleNewConn(conn *wrappedConn) { if s.acceptEarlyConns { // wait until the early connection is ready, the handshake fails, or the server is closed select { @@ -783,7 +793,7 @@ func (s *baseServer) handleNewConn(conn quicConn) { } select { - case s.connQueue <- conn: + case s.connQueue <- conn.Conn: default: conn.closeWithTransportError(ConnectionRefused) } diff --git a/vendor/github.com/quic-go/quic-go/stream.go b/vendor/github.com/quic-go/quic-go/stream.go index 9cd2695dd1..9c5a40e2a1 100644 --- a/vendor/github.com/quic-go/quic-go/stream.go +++ b/vendor/github.com/quic-go/quic-go/stream.go @@ -25,7 +25,7 @@ var errDeadline net.Error = &deadlineError{} // The streamSender is notified by the stream about various events. type streamSender interface { onHasConnectionData() - onHasStreamData(protocol.StreamID, sendStreamI) + onHasStreamData(protocol.StreamID, *SendStream) onHasStreamControlFrame(protocol.StreamID, streamControlFrameGetter) // must be called without holding the mutex that is acquired by closeForShutdown onStreamCompleted(protocol.StreamID) @@ -39,7 +39,7 @@ type uniStreamSender struct { onHasStreamControlFrameImpl func(protocol.StreamID, streamControlFrameGetter) } -func (s *uniStreamSender) onHasStreamData(id protocol.StreamID, str sendStreamI) { +func (s *uniStreamSender) onHasStreamData(id protocol.StreamID, str *SendStream) { s.streamSender.onHasStreamData(id, str) } func (s *uniStreamSender) onStreamCompleted(protocol.StreamID) { s.onStreamCompletedImpl() } @@ -49,30 +49,9 @@ func (s *uniStreamSender) onHasStreamControlFrame(id protocol.StreamID, str stre var _ streamSender = &uniStreamSender{} -type streamI interface { - Stream - closeForShutdown(error) - // for receiving - handleStreamFrame(*wire.StreamFrame, time.Time) error - handleResetStreamFrame(*wire.ResetStreamFrame, time.Time) error - // for sending - hasData() bool - handleStopSendingFrame(*wire.StopSendingFrame) - popStreamFrame(protocol.ByteCount, protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) - updateSendWindow(protocol.ByteCount) -} - -var ( - _ receiveStreamI = (streamI)(nil) - _ sendStreamI = (streamI)(nil) -) - -// A Stream assembles the data from StreamFrames and provides a super-convenient Read-Interface -// -// Read() and Write() may be called concurrently, but multiple calls to Read() or Write() individually must be synchronized manually. -type stream struct { - receiveStream - sendStream +type Stream struct { + receiveStr *ReceiveStream + sendStr *SendStream completedMutex sync.Mutex sender streamSender @@ -81,8 +60,9 @@ type stream struct { } var ( - _ Stream = &stream{} - _ streamControlFrameGetter = &receiveStream{} + _ outgoingStream = &Stream{} + _ sendStreamFrameHandler = &Stream{} + _ receiveStreamFrameHandler = &Stream{} ) // newStream creates a new Stream @@ -91,8 +71,8 @@ func newStream( streamID protocol.StreamID, sender streamSender, flowController flowcontrol.StreamFlowController, -) *stream { - s := &stream{sender: sender} +) *Stream { + s := &Stream{sender: sender} senderForSendStream := &uniStreamSender{ streamSender: sender, onStreamCompletedImpl: func() { @@ -105,7 +85,7 @@ func newStream( sender.onHasStreamControlFrame(streamID, s) }, } - s.sendStream = *newSendStream(ctx, streamID, senderForSendStream, flowController) + s.sendStr = newSendStream(ctx, streamID, senderForSendStream, flowController) senderForReceiveStream := &uniStreamSender{ streamSender: sender, onStreamCompletedImpl: func() { @@ -118,45 +98,113 @@ func newStream( sender.onHasStreamControlFrame(streamID, s) }, } - s.receiveStream = *newReceiveStream(streamID, senderForReceiveStream, flowController) + s.receiveStr = newReceiveStream(streamID, senderForReceiveStream, flowController) return s } -// need to define StreamID() here, since both receiveStream and readStream have a StreamID() -func (s *stream) StreamID() protocol.StreamID { +// StreamID returns the stream ID. +func (s *Stream) StreamID() protocol.StreamID { // the result is same for receiveStream and sendStream - return s.sendStream.StreamID() + return s.sendStr.StreamID() +} + +// Read reads data from the stream. +// Read can be made to time out using [Stream.SetReadDeadline] and [Stream.SetDeadline]. +// If the stream was canceled, the error is a [StreamError]. +func (s *Stream) Read(p []byte) (int, error) { + return s.receiveStr.Read(p) +} + +// Write writes data to the stream. +// Write can be made to time out using [Stream.SetWriteDeadline] or [Stream.SetDeadline]. +// If the stream was canceled, the error is a [StreamError]. +func (s *Stream) Write(p []byte) (int, error) { + return s.sendStr.Write(p) +} + +// CancelWrite aborts sending on this stream. +// See [SendStream.CancelWrite] for more details. +func (s *Stream) CancelWrite(errorCode StreamErrorCode) { + s.sendStr.CancelWrite(errorCode) +} + +// CancelRead aborts receiving on this stream. +// See [ReceiveStream.CancelRead] for more details. +func (s *Stream) CancelRead(errorCode StreamErrorCode) { + s.receiveStr.CancelRead(errorCode) +} + +// The Context is canceled as soon as the write-side of the stream is closed. +// See [SendStream.Context] for more details. +func (s *Stream) Context() context.Context { + return s.sendStr.Context() } -func (s *stream) Close() error { - return s.sendStream.Close() +// Close closes the send-direction of the stream. +// It does not close the receive-direction of the stream. +func (s *Stream) Close() error { + return s.sendStr.Close() } -func (s *stream) getControlFrame(now time.Time) (_ ackhandler.Frame, ok, hasMore bool) { - f, ok, _ := s.sendStream.getControlFrame(now) +func (s *Stream) handleResetStreamFrame(frame *wire.ResetStreamFrame, rcvTime time.Time) error { + return s.receiveStr.handleResetStreamFrame(frame, rcvTime) +} + +func (s *Stream) handleStreamFrame(frame *wire.StreamFrame, rcvTime time.Time) error { + return s.receiveStr.handleStreamFrame(frame, rcvTime) +} + +func (s *Stream) handleStopSendingFrame(frame *wire.StopSendingFrame) { + s.sendStr.handleStopSendingFrame(frame) +} + +func (s *Stream) updateSendWindow(limit protocol.ByteCount) { + s.sendStr.updateSendWindow(limit) +} + +func (s *Stream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) { + return s.sendStr.popStreamFrame(maxBytes, v) +} + +func (s *Stream) getControlFrame(now time.Time) (_ ackhandler.Frame, ok, hasMore bool) { + f, ok, _ := s.sendStr.getControlFrame(now) if ok { return f, true, true } - return s.receiveStream.getControlFrame(now) + return s.receiveStr.getControlFrame(now) +} + +// SetReadDeadline sets the deadline for future Read calls. +// See [ReceiveStream.SetReadDeadline] for more details. +func (s *Stream) SetReadDeadline(t time.Time) error { + return s.receiveStr.SetReadDeadline(t) +} + +// SetWriteDeadline sets the deadline for future Write calls. +// See [SendStream.SetWriteDeadline] for more details. +func (s *Stream) SetWriteDeadline(t time.Time) error { + return s.sendStr.SetWriteDeadline(t) } -func (s *stream) SetDeadline(t time.Time) error { - _ = s.SetReadDeadline(t) // SetReadDeadline never errors - _ = s.SetWriteDeadline(t) // SetWriteDeadline never errors +// SetDeadline sets the read and write deadlines associated with the stream. +// It is equivalent to calling both SetReadDeadline and SetWriteDeadline. +func (s *Stream) SetDeadline(t time.Time) error { + _ = s.receiveStr.SetReadDeadline(t) // SetReadDeadline never errors + _ = s.sendStr.SetWriteDeadline(t) // SetWriteDeadline never errors return nil } // CloseForShutdown closes a stream abruptly. // It makes Read and Write unblock (and return the error) immediately. // The peer will NOT be informed about this: the stream is closed without sending a FIN or RST. -func (s *stream) closeForShutdown(err error) { - s.sendStream.closeForShutdown(err) - s.receiveStream.closeForShutdown(err) +func (s *Stream) closeForShutdown(err error) { + s.sendStr.closeForShutdown(err) + s.receiveStr.closeForShutdown(err) } // checkIfCompleted is called from the uniStreamSender, when one of the stream halves is completed. // It makes sure that the onStreamCompleted callback is only called if both receive and send side have completed. -func (s *stream) checkIfCompleted() { +func (s *Stream) checkIfCompleted() { if s.sendStreamCompleted && s.receiveStreamCompleted { s.sender.onStreamCompleted(s.StreamID()) } diff --git a/vendor/github.com/quic-go/quic-go/streams_map.go b/vendor/github.com/quic-go/quic-go/streams_map.go index 510b3e5919..7584744a68 100644 --- a/vendor/github.com/quic-go/quic-go/streams_map.go +++ b/vendor/github.com/quic-go/quic-go/streams_map.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "sync" + "time" "github.com/quic-go/quic-go/internal/flowcontrol" "github.com/quic-go/quic-go/internal/protocol" @@ -11,28 +12,7 @@ import ( "github.com/quic-go/quic-go/internal/wire" ) -type streamError struct { - message string - nums []protocol.StreamNum -} - -func (e streamError) Error() string { - return e.message -} - -func convertStreamError(err error, stype protocol.StreamType, pers protocol.Perspective) error { - strError, ok := err.(streamError) - if !ok { - return err - } - ids := make([]interface{}, len(strError.nums)) - for i, num := range strError.nums { - ids[i] = num.StreamID(stype, pers) - } - return fmt.Errorf(strError.Error(), ids...) -} - -// StreamLimitReachedError is returned from Connection.OpenStream and Connection.OpenUniStream +// StreamLimitReachedError is returned from Conn.OpenStream and Conn.OpenUniStream // when it is not possible to open a new stream because the number of opens streams reached // the peer's stream limit. type StreamLimitReachedError struct{} @@ -51,15 +31,13 @@ type streamsMap struct { newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController mutex sync.Mutex - outgoingBidiStreams *outgoingStreamsMap[streamI] - outgoingUniStreams *outgoingStreamsMap[sendStreamI] - incomingBidiStreams *incomingStreamsMap[streamI] - incomingUniStreams *incomingStreamsMap[receiveStreamI] + outgoingBidiStreams *outgoingStreamsMap[*Stream] + outgoingUniStreams *outgoingStreamsMap[*SendStream] + incomingBidiStreams *incomingStreamsMap[*Stream] + incomingUniStreams *incomingStreamsMap[*ReceiveStream] reset bool } -var _ streamManager = &streamsMap{} - func newStreamsMap( ctx context.Context, sender streamSender, @@ -85,41 +63,41 @@ func newStreamsMap( func (m *streamsMap) initMaps() { m.outgoingBidiStreams = newOutgoingStreamsMap( protocol.StreamTypeBidi, - func(num protocol.StreamNum) streamI { - id := num.StreamID(protocol.StreamTypeBidi, m.perspective) + func(id protocol.StreamID) *Stream { return newStream(m.ctx, id, m.sender, m.newFlowController(id)) }, m.queueControlFrame, + m.perspective, ) m.incomingBidiStreams = newIncomingStreamsMap( protocol.StreamTypeBidi, - func(num protocol.StreamNum) streamI { - id := num.StreamID(protocol.StreamTypeBidi, m.perspective.Opposite()) + func(id protocol.StreamID) *Stream { return newStream(m.ctx, id, m.sender, m.newFlowController(id)) }, m.maxIncomingBidiStreams, m.queueControlFrame, + m.perspective, ) m.outgoingUniStreams = newOutgoingStreamsMap( protocol.StreamTypeUni, - func(num protocol.StreamNum) sendStreamI { - id := num.StreamID(protocol.StreamTypeUni, m.perspective) + func(id protocol.StreamID) *SendStream { return newSendStream(m.ctx, id, m.sender, m.newFlowController(id)) }, m.queueControlFrame, + m.perspective, ) m.incomingUniStreams = newIncomingStreamsMap( protocol.StreamTypeUni, - func(num protocol.StreamNum) receiveStreamI { - id := num.StreamID(protocol.StreamTypeUni, m.perspective.Opposite()) + func(id protocol.StreamID) *ReceiveStream { return newReceiveStream(id, m.sender, m.newFlowController(id)) }, m.maxIncomingUniStreams, m.queueControlFrame, + m.perspective, ) } -func (m *streamsMap) OpenStream() (Stream, error) { +func (m *streamsMap) OpenStream() (*Stream, error) { m.mutex.Lock() reset := m.reset mm := m.outgoingBidiStreams @@ -127,11 +105,10 @@ func (m *streamsMap) OpenStream() (Stream, error) { if reset { return nil, Err0RTTRejected } - str, err := mm.OpenStream() - return str, convertStreamError(err, protocol.StreamTypeBidi, m.perspective) + return mm.OpenStream() } -func (m *streamsMap) OpenStreamSync(ctx context.Context) (Stream, error) { +func (m *streamsMap) OpenStreamSync(ctx context.Context) (*Stream, error) { m.mutex.Lock() reset := m.reset mm := m.outgoingBidiStreams @@ -139,11 +116,10 @@ func (m *streamsMap) OpenStreamSync(ctx context.Context) (Stream, error) { if reset { return nil, Err0RTTRejected } - str, err := mm.OpenStreamSync(ctx) - return str, convertStreamError(err, protocol.StreamTypeBidi, m.perspective) + return mm.OpenStreamSync(ctx) } -func (m *streamsMap) OpenUniStream() (SendStream, error) { +func (m *streamsMap) OpenUniStream() (*SendStream, error) { m.mutex.Lock() reset := m.reset mm := m.outgoingUniStreams @@ -151,11 +127,10 @@ func (m *streamsMap) OpenUniStream() (SendStream, error) { if reset { return nil, Err0RTTRejected } - str, err := mm.OpenStream() - return str, convertStreamError(err, protocol.StreamTypeBidi, m.perspective) + return mm.OpenStream() } -func (m *streamsMap) OpenUniStreamSync(ctx context.Context) (SendStream, error) { +func (m *streamsMap) OpenUniStreamSync(ctx context.Context) (*SendStream, error) { m.mutex.Lock() reset := m.reset mm := m.outgoingUniStreams @@ -163,11 +138,10 @@ func (m *streamsMap) OpenUniStreamSync(ctx context.Context) (SendStream, error) if reset { return nil, Err0RTTRejected } - str, err := mm.OpenStreamSync(ctx) - return str, convertStreamError(err, protocol.StreamTypeUni, m.perspective) + return mm.OpenStreamSync(ctx) } -func (m *streamsMap) AcceptStream(ctx context.Context) (Stream, error) { +func (m *streamsMap) AcceptStream(ctx context.Context) (*Stream, error) { m.mutex.Lock() reset := m.reset mm := m.incomingBidiStreams @@ -175,11 +149,10 @@ func (m *streamsMap) AcceptStream(ctx context.Context) (Stream, error) { if reset { return nil, Err0RTTRejected } - str, err := mm.AcceptStream(ctx) - return str, convertStreamError(err, protocol.StreamTypeBidi, m.perspective.Opposite()) + return mm.AcceptStream(ctx) } -func (m *streamsMap) AcceptUniStream(ctx context.Context) (ReceiveStream, error) { +func (m *streamsMap) AcceptUniStream(ctx context.Context) (*ReceiveStream, error) { m.mutex.Lock() reset := m.reset mm := m.incomingUniStreams @@ -187,109 +160,167 @@ func (m *streamsMap) AcceptUniStream(ctx context.Context) (ReceiveStream, error) if reset { return nil, Err0RTTRejected } - str, err := mm.AcceptStream(ctx) - return str, convertStreamError(err, protocol.StreamTypeUni, m.perspective.Opposite()) + return mm.AcceptStream(ctx) } func (m *streamsMap) DeleteStream(id protocol.StreamID) error { - num := id.StreamNum() switch id.Type() { case protocol.StreamTypeUni: if id.InitiatedBy() == m.perspective { - return convertStreamError(m.outgoingUniStreams.DeleteStream(num), protocol.StreamTypeUni, m.perspective) + return m.outgoingUniStreams.DeleteStream(id) } - return convertStreamError(m.incomingUniStreams.DeleteStream(num), protocol.StreamTypeUni, m.perspective.Opposite()) + return m.incomingUniStreams.DeleteStream(id) case protocol.StreamTypeBidi: if id.InitiatedBy() == m.perspective { - return convertStreamError(m.outgoingBidiStreams.DeleteStream(num), protocol.StreamTypeBidi, m.perspective) + return m.outgoingBidiStreams.DeleteStream(id) } - return convertStreamError(m.incomingBidiStreams.DeleteStream(num), protocol.StreamTypeBidi, m.perspective.Opposite()) + return m.incomingBidiStreams.DeleteStream(id) } panic("") } -func (m *streamsMap) GetOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) { - str, err := m.getOrOpenReceiveStream(id) - if err != nil { - return nil, &qerr.TransportError{ - ErrorCode: qerr.StreamStateError, - ErrorMessage: err.Error(), - } +func (m *streamsMap) HandleMaxStreamsFrame(f *wire.MaxStreamsFrame) { + switch f.Type { + case protocol.StreamTypeUni: + m.outgoingUniStreams.SetMaxStream(f.MaxStreamNum.StreamID(protocol.StreamTypeUni, m.perspective)) + case protocol.StreamTypeBidi: + m.outgoingBidiStreams.SetMaxStream(f.MaxStreamNum.StreamID(protocol.StreamTypeBidi, m.perspective)) } - return str, nil } -func (m *streamsMap) getOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) { - num := id.StreamNum() +type sendStreamFrameHandler interface { + updateSendWindow(protocol.ByteCount) + handleStopSendingFrame(*wire.StopSendingFrame) +} + +func (m *streamsMap) getSendStream(id protocol.StreamID) (sendStreamFrameHandler, error) { switch id.Type() { case protocol.StreamTypeUni: - if id.InitiatedBy() == m.perspective { + if id.InitiatedBy() != m.perspective { // an outgoing unidirectional stream is a send stream, not a receive stream - return nil, fmt.Errorf("peer attempted to open receive stream %d", id) + return nil, &qerr.TransportError{ + ErrorCode: qerr.StreamStateError, + ErrorMessage: fmt.Sprintf("invalid frame for send stream %d", id), + } + } + str, err := m.outgoingUniStreams.GetStream(id) + if str == nil || err != nil { + return nil, err } - str, err := m.incomingUniStreams.GetOrOpenStream(num) - return str, convertStreamError(err, protocol.StreamTypeUni, m.perspective) + return str, nil case protocol.StreamTypeBidi: - var str receiveStreamI - var err error if id.InitiatedBy() == m.perspective { - str, err = m.outgoingBidiStreams.GetStream(num) - } else { - str, err = m.incomingBidiStreams.GetOrOpenStream(num) + str, err := m.outgoingBidiStreams.GetStream(id) + if str == nil || err != nil { + return nil, err + } + return str, nil + } + str, err := m.incomingBidiStreams.GetOrOpenStream(id) + if str == nil || err != nil { + return nil, err } - return str, convertStreamError(err, protocol.StreamTypeBidi, id.InitiatedBy()) + return str, nil } - panic("") + panic("unreachable") } -func (m *streamsMap) GetOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) { - str, err := m.getOrOpenSendStream(id) +func (m *streamsMap) HandleMaxStreamDataFrame(f *wire.MaxStreamDataFrame) error { + str, err := m.getSendStream(f.StreamID) if err != nil { - return nil, &qerr.TransportError{ - ErrorCode: qerr.StreamStateError, - ErrorMessage: err.Error(), - } + return err + } + if str == nil { // stream already deleted + return nil } - return str, nil + str.updateSendWindow(f.MaximumStreamData) + return nil } -func (m *streamsMap) getOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) { - num := id.StreamNum() +func (m *streamsMap) HandleStopSendingFrame(f *wire.StopSendingFrame) error { + str, err := m.getSendStream(f.StreamID) + if err != nil { + return err + } + if str == nil { // stream already deleted + return nil + } + str.handleStopSendingFrame(f) + return nil +} + +type receiveStreamFrameHandler interface { + handleResetStreamFrame(*wire.ResetStreamFrame, time.Time) error + handleStreamFrame(*wire.StreamFrame, time.Time) error +} + +func (m *streamsMap) getReceiveStream(id protocol.StreamID) (receiveStreamFrameHandler, error) { switch id.Type() { case protocol.StreamTypeUni: + // an outgoing unidirectional stream is a send stream, not a receive stream if id.InitiatedBy() == m.perspective { - str, err := m.outgoingUniStreams.GetStream(num) - return str, convertStreamError(err, protocol.StreamTypeUni, m.perspective) + return nil, &qerr.TransportError{ + ErrorCode: qerr.StreamStateError, + ErrorMessage: fmt.Sprintf("invalid frame for receive stream %d", id), + } } - // an incoming unidirectional stream is a receive stream, not a send stream - return nil, fmt.Errorf("peer attempted to open send stream %d", id) + str, err := m.incomingUniStreams.GetOrOpenStream(id) + if err != nil || str == nil { + return nil, err + } + return str, nil case protocol.StreamTypeBidi: - var str sendStreamI + var str *Stream var err error if id.InitiatedBy() == m.perspective { - str, err = m.outgoingBidiStreams.GetStream(num) + str, err = m.outgoingBidiStreams.GetStream(id) } else { - str, err = m.incomingBidiStreams.GetOrOpenStream(num) + str, err = m.incomingBidiStreams.GetOrOpenStream(id) + } + if str == nil || err != nil { + return nil, err } - return str, convertStreamError(err, protocol.StreamTypeBidi, id.InitiatedBy()) + return str, nil } - panic("") + panic("unreachable") } -func (m *streamsMap) HandleMaxStreamsFrame(f *wire.MaxStreamsFrame) { - switch f.Type { - case protocol.StreamTypeUni: - m.outgoingUniStreams.SetMaxStream(f.MaxStreamNum) - case protocol.StreamTypeBidi: - m.outgoingBidiStreams.SetMaxStream(f.MaxStreamNum) +func (m *streamsMap) HandleStreamDataBlockedFrame(f *wire.StreamDataBlockedFrame) error { + if _, err := m.getReceiveStream(f.StreamID); err != nil { + return err + } + // We don't need to do anything in response to a STREAM_DATA_BLOCKED frame, + // but we need to make sure that the stream ID is valid. + return nil // we don't need to do anything in response to a STREAM_DATA_BLOCKED frame +} + +func (m *streamsMap) HandleResetStreamFrame(f *wire.ResetStreamFrame, rcvTime time.Time) error { + str, err := m.getReceiveStream(f.StreamID) + if err != nil { + return err + } + if str == nil { // stream already deleted + return nil + } + return str.handleResetStreamFrame(f, rcvTime) +} + +func (m *streamsMap) HandleStreamFrame(f *wire.StreamFrame, rcvTime time.Time) error { + str, err := m.getReceiveStream(f.StreamID) + if err != nil { + return err + } + if str == nil { // stream already deleted + return nil } + return str.handleStreamFrame(f, rcvTime) } func (m *streamsMap) UpdateLimits(p *wire.TransportParameters) { m.outgoingBidiStreams.UpdateSendWindow(p.InitialMaxStreamDataBidiRemote) - m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamNum) + m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamNum.StreamID(protocol.StreamTypeBidi, m.perspective)) m.outgoingUniStreams.UpdateSendWindow(p.InitialMaxStreamDataUni) - m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamNum) + m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamNum.StreamID(protocol.StreamTypeUni, m.perspective)) } func (m *streamsMap) CloseWithError(err error) { diff --git a/vendor/github.com/quic-go/quic-go/streams_map_incoming.go b/vendor/github.com/quic-go/quic-go/streams_map_incoming.go index 18ec6f998b..c714eaf10f 100644 --- a/vendor/github.com/quic-go/quic-go/streams_map_incoming.go +++ b/vendor/github.com/quic-go/quic-go/streams_map_incoming.go @@ -2,9 +2,11 @@ package quic import ( "context" + "fmt" "sync" "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/wire" ) @@ -24,14 +26,14 @@ type incomingStreamsMap[T incomingStream] struct { newStreamChan chan struct{} streamType protocol.StreamType - streams map[protocol.StreamNum]incomingStreamEntry[T] + streams map[protocol.StreamID]incomingStreamEntry[T] - nextStreamToAccept protocol.StreamNum // the next stream that will be returned by AcceptStream() - nextStreamToOpen protocol.StreamNum // the highest stream that the peer opened - maxStream protocol.StreamNum // the highest stream that the peer is allowed to open - maxNumStreams uint64 // maximum number of streams + nextStreamToAccept protocol.StreamID // the next stream that will be returned by AcceptStream() + nextStreamToOpen protocol.StreamID // the highest stream that the peer opened + maxStream protocol.StreamID // the highest stream that the peer is allowed to open + maxNumStreams uint64 // maximum number of streams - newStream func(protocol.StreamNum) T + newStream func(protocol.StreamID) T queueMaxStreamID func(*wire.MaxStreamsFrame) closeErr error @@ -39,19 +41,31 @@ type incomingStreamsMap[T incomingStream] struct { func newIncomingStreamsMap[T incomingStream]( streamType protocol.StreamType, - newStream func(protocol.StreamNum) T, + newStream func(protocol.StreamID) T, maxStreams uint64, queueControlFrame func(wire.Frame), + pers protocol.Perspective, ) *incomingStreamsMap[T] { + var nextStreamToAccept protocol.StreamID + switch { + case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveServer: + nextStreamToAccept = protocol.FirstIncomingBidiStreamServer + case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveClient: + nextStreamToAccept = protocol.FirstIncomingBidiStreamClient + case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveServer: + nextStreamToAccept = protocol.FirstIncomingUniStreamServer + case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveClient: + nextStreamToAccept = protocol.FirstIncomingUniStreamClient + } return &incomingStreamsMap[T]{ newStreamChan: make(chan struct{}, 1), streamType: streamType, - streams: make(map[protocol.StreamNum]incomingStreamEntry[T]), - maxStream: protocol.StreamNum(maxStreams), + streams: make(map[protocol.StreamID]incomingStreamEntry[T]), + maxStream: protocol.StreamNum(maxStreams).StreamID(streamType, pers.Opposite()), maxNumStreams: maxStreams, newStream: newStream, - nextStreamToOpen: 1, - nextStreamToAccept: 1, + nextStreamToOpen: nextStreamToAccept, + nextStreamToAccept: nextStreamToAccept, queueMaxStreamID: func(f *wire.MaxStreamsFrame) { queueControlFrame(f) }, } } @@ -65,16 +79,16 @@ func (m *incomingStreamsMap[T]) AcceptStream(ctx context.Context) (T, error) { m.mutex.Lock() - var num protocol.StreamNum + var id protocol.StreamID var entry incomingStreamEntry[T] for { - num = m.nextStreamToAccept + id = m.nextStreamToAccept if m.closeErr != nil { m.mutex.Unlock() return *new(T), m.closeErr } var ok bool - entry, ok = m.streams[num] + entry, ok = m.streams[id] if ok { break } @@ -86,10 +100,10 @@ func (m *incomingStreamsMap[T]) AcceptStream(ctx context.Context) (T, error) { } m.mutex.Lock() } - m.nextStreamToAccept++ + m.nextStreamToAccept += 4 // If this stream was completed before being accepted, we can delete it now. if entry.shouldDelete { - if err := m.deleteStream(num); err != nil { + if err := m.deleteStream(id); err != nil { m.mutex.Unlock() return *new(T), err } @@ -98,22 +112,22 @@ func (m *incomingStreamsMap[T]) AcceptStream(ctx context.Context) (T, error) { return entry.stream, nil } -func (m *incomingStreamsMap[T]) GetOrOpenStream(num protocol.StreamNum) (T, error) { +func (m *incomingStreamsMap[T]) GetOrOpenStream(id protocol.StreamID) (T, error) { m.mutex.RLock() - if num > m.maxStream { + if id > m.maxStream { m.mutex.RUnlock() - return *new(T), streamError{ - message: "peer tried to open stream %d (current limit: %d)", - nums: []protocol.StreamNum{num, m.maxStream}, + return *new(T), &qerr.TransportError{ + ErrorCode: qerr.StreamLimitError, + ErrorMessage: fmt.Sprintf("peer tried to open stream %d (current limit: %d)", id, m.maxStream), } } // if the num is smaller than the highest we accepted // * this stream exists in the map, and we can return it, or // * this stream was already closed, then we can return the nil - if num < m.nextStreamToOpen { + if id < m.nextStreamToOpen { var s T // If the stream was already queued for deletion, and is just waiting to be accepted, don't return it. - if entry, ok := m.streams[num]; ok && !entry.shouldDelete { + if entry, ok := m.streams[id]; ok && !entry.shouldDelete { s = entry.stream } m.mutex.RUnlock() @@ -125,59 +139,59 @@ func (m *incomingStreamsMap[T]) GetOrOpenStream(num protocol.StreamNum) (T, erro // no need to check the two error conditions from above again // * maxStream can only increase, so if the id was valid before, it definitely is valid now // * highestStream is only modified by this function - for newNum := m.nextStreamToOpen; newNum <= num; newNum++ { + for newNum := m.nextStreamToOpen; newNum <= id; newNum += 4 { m.streams[newNum] = incomingStreamEntry[T]{stream: m.newStream(newNum)} select { case m.newStreamChan <- struct{}{}: default: } } - m.nextStreamToOpen = num + 1 - entry := m.streams[num] + m.nextStreamToOpen = id + 4 + entry := m.streams[id] m.mutex.Unlock() return entry.stream, nil } -func (m *incomingStreamsMap[T]) DeleteStream(num protocol.StreamNum) error { +func (m *incomingStreamsMap[T]) DeleteStream(id protocol.StreamID) error { m.mutex.Lock() defer m.mutex.Unlock() - return m.deleteStream(num) + if err := m.deleteStream(id); err != nil { + return &qerr.TransportError{ + ErrorCode: qerr.StreamStateError, + ErrorMessage: err.Error(), + } + } + return nil } -func (m *incomingStreamsMap[T]) deleteStream(num protocol.StreamNum) error { - if _, ok := m.streams[num]; !ok { - return streamError{ - message: "tried to delete unknown incoming stream %d", - nums: []protocol.StreamNum{num}, - } +func (m *incomingStreamsMap[T]) deleteStream(id protocol.StreamID) error { + if _, ok := m.streams[id]; !ok { + return fmt.Errorf("tried to delete unknown incoming stream %d", id) } // Don't delete this stream yet, if it was not yet accepted. // Just save it to streamsToDelete map, to make sure it is deleted as soon as it gets accepted. - if num >= m.nextStreamToAccept { - entry, ok := m.streams[num] + if id >= m.nextStreamToAccept { + entry, ok := m.streams[id] if ok && entry.shouldDelete { - return streamError{ - message: "tried to delete incoming stream %d multiple times", - nums: []protocol.StreamNum{num}, - } + return fmt.Errorf("tried to delete incoming stream %d multiple times", id) } entry.shouldDelete = true - m.streams[num] = entry // can't assign to struct in map, so we need to reassign + m.streams[id] = entry // can't assign to struct in map, so we need to reassign return nil } - delete(m.streams, num) + delete(m.streams, id) // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream if m.maxNumStreams > uint64(len(m.streams)) { - maxStream := m.nextStreamToOpen + protocol.StreamNum(m.maxNumStreams-uint64(len(m.streams))) - 1 - // Never send a value larger than protocol.MaxStreamCount. - if maxStream <= protocol.MaxStreamCount { + maxStream := m.nextStreamToOpen + 4*protocol.StreamID(m.maxNumStreams-uint64(len(m.streams))-1) + // never send a value larger than the maximum value for a stream number + if maxStream <= protocol.MaxStreamID { m.maxStream = maxStream m.queueMaxStreamID(&wire.MaxStreamsFrame{ Type: m.streamType, - MaxStreamNum: m.maxStream, + MaxStreamNum: m.maxStream.StreamNum(), }) } } diff --git a/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go index d4c1825929..28b2179f1b 100644 --- a/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go +++ b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go @@ -2,10 +2,12 @@ package quic import ( "context" + "fmt" "slices" "sync" "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/wire" ) @@ -18,15 +20,15 @@ type outgoingStreamsMap[T outgoingStream] struct { mutex sync.RWMutex streamType protocol.StreamType - streams map[protocol.StreamNum]T + streams map[protocol.StreamID]T openQueue []chan struct{} - nextStream protocol.StreamNum // stream ID of the stream returned by OpenStream(Sync) - maxStream protocol.StreamNum // the maximum stream ID we're allowed to open - blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream + nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync) + maxStream protocol.StreamID // the maximum stream ID we're allowed to open + blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream - newStream func(protocol.StreamNum) T + newStream func(protocol.StreamID) T queueStreamIDBlocked func(*wire.StreamsBlockedFrame) closeErr error @@ -34,14 +36,26 @@ type outgoingStreamsMap[T outgoingStream] struct { func newOutgoingStreamsMap[T outgoingStream]( streamType protocol.StreamType, - newStream func(protocol.StreamNum) T, + newStream func(protocol.StreamID) T, queueControlFrame func(wire.Frame), + pers protocol.Perspective, ) *outgoingStreamsMap[T] { + var nextStream protocol.StreamID + switch { + case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveServer: + nextStream = protocol.FirstOutgoingBidiStreamServer + case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveClient: + nextStream = protocol.FirstOutgoingBidiStreamClient + case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveServer: + nextStream = protocol.FirstOutgoingUniStreamServer + case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveClient: + nextStream = protocol.FirstOutgoingUniStreamClient + } return &outgoingStreamsMap[T]{ streamType: streamType, - streams: make(map[protocol.StreamNum]T), + streams: make(map[protocol.StreamID]T), maxStream: protocol.InvalidStreamNum, - nextStream: 1, + nextStream: nextStream, newStream: newStream, queueStreamIDBlocked: func(f *wire.StreamsBlockedFrame) { queueControlFrame(f) }, } @@ -114,7 +128,7 @@ func (m *outgoingStreamsMap[T]) OpenStreamSync(ctx context.Context) (T, error) { func (m *outgoingStreamsMap[T]) openStream() T { s := m.newStream(m.nextStream) m.streams[m.nextStream] = s - m.nextStream++ + m.nextStream += 4 return s } @@ -125,55 +139,55 @@ func (m *outgoingStreamsMap[T]) maybeSendBlockedFrame() { return } - var streamNum protocol.StreamNum - if m.maxStream != protocol.InvalidStreamNum { - streamNum = m.maxStream + var streamLimit protocol.StreamNum + if m.maxStream != protocol.InvalidStreamID { + streamLimit = m.maxStream.StreamNum() } m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{ Type: m.streamType, - StreamLimit: streamNum, + StreamLimit: streamLimit, }) m.blockedSent = true } -func (m *outgoingStreamsMap[T]) GetStream(num protocol.StreamNum) (T, error) { +func (m *outgoingStreamsMap[T]) GetStream(id protocol.StreamID) (T, error) { m.mutex.RLock() - if num >= m.nextStream { + if id >= m.nextStream { m.mutex.RUnlock() - return *new(T), streamError{ - message: "peer attempted to open stream %d", - nums: []protocol.StreamNum{num}, + return *new(T), &qerr.TransportError{ + ErrorCode: qerr.StreamStateError, + ErrorMessage: fmt.Sprintf("peer attempted to open stream %d", id), } } - s := m.streams[num] + s := m.streams[id] m.mutex.RUnlock() return s, nil } -func (m *outgoingStreamsMap[T]) DeleteStream(num protocol.StreamNum) error { +func (m *outgoingStreamsMap[T]) DeleteStream(id protocol.StreamID) error { m.mutex.Lock() defer m.mutex.Unlock() - if _, ok := m.streams[num]; !ok { - return streamError{ - message: "tried to delete unknown outgoing stream %d", - nums: []protocol.StreamNum{num}, + if _, ok := m.streams[id]; !ok { + return &qerr.TransportError{ + ErrorCode: qerr.StreamStateError, + ErrorMessage: fmt.Sprintf("tried to delete unknown outgoing stream %d", id), } } - delete(m.streams, num) + delete(m.streams, id) return nil } -func (m *outgoingStreamsMap[T]) SetMaxStream(num protocol.StreamNum) { +func (m *outgoingStreamsMap[T]) SetMaxStream(id protocol.StreamID) { m.mutex.Lock() defer m.mutex.Unlock() - if num <= m.maxStream { + if id <= m.maxStream { return } - m.maxStream = num + m.maxStream = id m.blockedSent = false - if m.maxStream < m.nextStream-1+protocol.StreamNum(len(m.openQueue)) { + if m.maxStream < m.nextStream-4+4*protocol.StreamID(len(m.openQueue)) { m.maybeSendBlockedFrame() } m.maybeUnblockOpenSync() diff --git a/vendor/github.com/quic-go/quic-go/tools.go b/vendor/github.com/quic-go/quic-go/tools.go index d00ce748d6..8181df6d36 100644 --- a/vendor/github.com/quic-go/quic-go/tools.go +++ b/vendor/github.com/quic-go/quic-go/tools.go @@ -3,6 +3,5 @@ package quic import ( - _ "github.com/onsi/ginkgo/v2/ginkgo" _ "go.uber.org/mock/mockgen" ) diff --git a/vendor/github.com/quic-go/quic-go/transport.go b/vendor/github.com/quic-go/quic-go/transport.go index 525adb3f1c..2f105298be 100644 --- a/vendor/github.com/quic-go/quic-go/transport.go +++ b/vendor/github.com/quic-go/quic-go/transport.go @@ -124,7 +124,7 @@ type Transport struct { // lifetime of the connection: // * the context passed to crypto/tls (and used on the tls.ClientHelloInfo) // * the context used in Config.Tracer - // * the context returned from Connection.Context + // * the context returned from Conn.Context // * the context returned from SendStream.Context // It is not used for dialed connections. ConnContext func(context.Context, *ClientInfo) (context.Context, error) @@ -133,11 +133,10 @@ type Transport struct { // Tracer.Close is called when the transport is closed. Tracer *logging.Tracer - connMx sync.Mutex + mutex sync.Mutex handlers map[protocol.ConnectionID]packetHandler resetTokens map[protocol.StatelessResetToken]packetHandler - mutex sync.Mutex initOnce sync.Once initErr error @@ -234,16 +233,16 @@ func (t *Transport) createServer(tlsConf *tls.Config, conf *Config, allow0RTT bo } // Dial dials a new connection to a remote host (not using 0-RTT). -func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) { +func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) { return t.dial(ctx, addr, "", tlsConf, conf, false) } // DialEarly dials a new connection, attempting to use 0-RTT if possible. -func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { +func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) { return t.dial(ctx, addr, "", tlsConf, conf, true) } -func (t *Transport) dial(ctx context.Context, addr net.Addr, host string, tlsConf *tls.Config, conf *Config, use0RTT bool) (EarlyConnection, error) { +func (t *Transport) dial(ctx context.Context, addr net.Addr, host string, tlsConf *tls.Config, conf *Config, use0RTT bool) (*Conn, error) { if err := t.init(t.isSingleUse); err != nil { return nil, err } @@ -273,7 +272,7 @@ func (t *Transport) doDial( hasNegotiatedVersion bool, use0RTT bool, version protocol.Version, -) (quicConn, error) { +) (*Conn, error) { srcConnID, err := t.connIDGenerator.GenerateConnectionID() if err != nil { return nil, err @@ -320,15 +319,14 @@ func (t *Transport) doDial( logger, version, ) - t.connMx.Lock() t.handlers[srcConnID] = conn - t.connMx.Unlock() t.mutex.Unlock() // The error channel needs to be buffered, as the run loop will continue running // after doDial returns (if the handshake is successful). + // Similarly, the recreateChan needs to be buffered; in case a different case is selected. errChan := make(chan error, 1) - recreateChan := make(chan errCloseForRecreating) + recreateChan := make(chan errCloseForRecreating, 1) go func() { err := conn.run() var recreateErr *errCloseForRecreating @@ -352,7 +350,7 @@ func (t *Transport) doDial( select { case <-ctx.Done(): conn.destroy(nil) - // wait until the Go routine that called Connection.run() returns + // wait until the Go routine that called Conn.run() returns select { case <-errChan: case <-recreateChan: @@ -372,10 +370,10 @@ func (t *Transport) doDial( return nil, err case <-earlyConnChan: // ready to send 0-RTT data - return conn, nil + return conn.Conn, nil case <-conn.HandshakeComplete(): // handshake successfully completed - return conn, nil + return conn.Conn, nil } } @@ -458,8 +456,12 @@ func (t *Transport) runSendQueue() { } // Close stops listening for UDP datagrams on the Transport.Conn. -// If any listener was started, it will be closed as well. -// It is invalid to start new listeners or connections after that. +// It abruptly terminates all existing connections, without sending a CONNECTION_CLOSE +// to the peers. It is the application's responsibility to cleanly terminate existing +// connections prior to calling Close. +// +// If a server was started, it will be closed as well. +// It is not possible to start any new server or dial new connections after that. func (t *Transport) Close() error { // avoid race condition if the transport is currently being initialized t.init(false) @@ -488,8 +490,6 @@ func (t *Transport) closeServer() { t.closeErr = ErrServerClosed } - t.connMx.Lock() - defer t.connMx.Unlock() if len(t.handlers) == 0 { t.maybeStopListening() } @@ -497,16 +497,24 @@ func (t *Transport) closeServer() { func (t *Transport) close(e error) { t.mutex.Lock() - defer t.mutex.Unlock() if t.closeErr != nil { + t.mutex.Unlock() return } e = &errTransportClosed{err: e} + t.closeErr = e + server := t.server + t.server = nil + if server != nil { + t.mutex.Unlock() + server.close(e, true) + t.mutex.Lock() + } + // Close existing connections var wg sync.WaitGroup - t.connMx.Lock() for _, handler := range t.handlers { wg.Add(1) go func(handler packetHandler) { @@ -514,16 +522,12 @@ func (t *Transport) close(e error) { wg.Done() }(handler) } - t.connMx.Unlock() + t.mutex.Unlock() // closing connections requires releasing transport mutex wg.Wait() - if t.server != nil { - t.server.close(e, false) - } if t.Tracer != nil && t.Tracer.Close != nil { t.Tracer.Close() } - t.closeErr = e } // only print warnings about the UDP receive buffer size once @@ -669,9 +673,9 @@ func (t *Transport) maybeHandleStatelessReset(data []byte) bool { } token := protocol.StatelessResetToken(data[len(data)-16:]) - t.connMx.Lock() + t.mutex.Lock() conn, ok := t.resetTokens[token] - t.connMx.Unlock() + t.mutex.Unlock() if ok { t.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token) @@ -744,8 +748,8 @@ type packetHandlerMap Transport var _ connRunner = &packetHandlerMap{} func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) bool /* was added */ { - h.connMx.Lock() - defer h.connMx.Unlock() + h.mutex.Lock() + defer h.mutex.Unlock() if _, ok := h.handlers[id]; ok { h.logger.Debugf("Not adding connection ID %s, as it already exists.", id) @@ -757,27 +761,27 @@ func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) } func (h *packetHandlerMap) Get(connID protocol.ConnectionID) (packetHandler, bool) { - h.connMx.Lock() - defer h.connMx.Unlock() + h.mutex.Lock() + defer h.mutex.Unlock() handler, ok := h.handlers[connID] return handler, ok } func (h *packetHandlerMap) AddResetToken(token protocol.StatelessResetToken, handler packetHandler) { - h.connMx.Lock() + h.mutex.Lock() h.resetTokens[token] = handler - h.connMx.Unlock() + h.mutex.Unlock() } func (h *packetHandlerMap) RemoveResetToken(token protocol.StatelessResetToken) { - h.connMx.Lock() + h.mutex.Lock() delete(h.resetTokens, token) - h.connMx.Unlock() + h.mutex.Unlock() } func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, handler packetHandler) bool { - h.connMx.Lock() - defer h.connMx.Unlock() + h.mutex.Lock() + defer h.mutex.Unlock() if _, ok := h.handlers[clientDestConnID]; ok { h.logger.Debugf("Not adding connection ID %s for a new connection, as it already exists.", clientDestConnID) @@ -790,9 +794,9 @@ func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.Co } func (h *packetHandlerMap) Remove(id protocol.ConnectionID) { - h.connMx.Lock() + h.mutex.Lock() delete(h.handlers, id) - h.connMx.Unlock() + h.mutex.Unlock() h.logger.Debugf("Removing connection ID %s.", id) } @@ -818,25 +822,23 @@ func (h *packetHandlerMap) ReplaceWithClosed(ids []protocol.ConnectionID, connCl handler = newClosedRemoteConn() } - h.connMx.Lock() + h.mutex.Lock() for _, id := range ids { h.handlers[id] = handler } - h.connMx.Unlock() + h.mutex.Unlock() h.logger.Debugf("Replacing connection for connection IDs %s with a closed connection.", ids) time.AfterFunc(expiry, func() { - h.connMx.Lock() + h.mutex.Lock() for _, id := range ids { delete(h.handlers, id) } if len(h.handlers) == 0 { t := (*Transport)(h) - t.mutex.Lock() t.maybeStopListening() - t.mutex.Unlock() } - h.connMx.Unlock() + h.mutex.Unlock() h.logger.Debugf("Removing connection IDs %s for a closed connection after it has been retired.", ids) }) } diff --git a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/vendor/golang.org/x/tools/go/ast/inspector/inspector.go deleted file mode 100644 index 674490a65b..0000000000 --- a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package inspector provides helper functions for traversal over the -// syntax trees of a package, including node filtering by type, and -// materialization of the traversal stack. -// -// During construction, the inspector does a complete traversal and -// builds a list of push/pop events and their node type. Subsequent -// method calls that request a traversal scan this list, rather than walk -// the AST, and perform type filtering using efficient bit sets. -// This representation is sometimes called a "balanced parenthesis tree." -// -// Experiments suggest the inspector's traversals are about 2.5x faster -// than ast.Inspect, but it may take around 5 traversals for this -// benefit to amortize the inspector's construction cost. -// If efficiency is the primary concern, do not use Inspector for -// one-off traversals. -package inspector - -// There are four orthogonal features in a traversal: -// 1 type filtering -// 2 pruning -// 3 postorder calls to f -// 4 stack -// Rather than offer all of them in the API, -// only a few combinations are exposed: -// - Preorder is the fastest and has fewest features, -// but is the most commonly needed traversal. -// - Nodes and WithStack both provide pruning and postorder calls, -// even though few clients need it, because supporting two versions -// is not justified. -// More combinations could be supported by expressing them as -// wrappers around a more generic traversal, but this was measured -// and found to degrade performance significantly (30%). - -import ( - "go/ast" - _ "unsafe" - - "golang.org/x/tools/internal/astutil/edge" -) - -// An Inspector provides methods for inspecting -// (traversing) the syntax trees of a package. -type Inspector struct { - events []event -} - -//go:linkname events golang.org/x/tools/go/ast/inspector.events -func events(in *Inspector) []event { return in.events } - -//go:linkname packEdgeKindAndIndex golang.org/x/tools/go/ast/inspector.packEdgeKindAndIndex -func packEdgeKindAndIndex(ek edge.Kind, index int) int32 { - return int32(uint32(index+1)<<7 | uint32(ek)) -} - -// unpackEdgeKindAndIndex unpacks the edge kind and edge index (within -// an []ast.Node slice) from the parent field of a pop event. -// -//go:linkname unpackEdgeKindAndIndex golang.org/x/tools/go/ast/inspector.unpackEdgeKindAndIndex -func unpackEdgeKindAndIndex(x int32) (edge.Kind, int) { - // The "parent" field of a pop node holds the - // edge Kind in the lower 7 bits and the index+1 - // in the upper 25. - return edge.Kind(x & 0x7f), int(x>>7) - 1 -} - -// New returns an Inspector for the specified syntax trees. -func New(files []*ast.File) *Inspector { - return &Inspector{traverse(files)} -} - -// An event represents a push or a pop -// of an ast.Node during a traversal. -type event struct { - node ast.Node - typ uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events - index int32 // index of corresponding push or pop event - parent int32 // index of parent's push node (push nodes only), or packed edge kind/index (pop nodes only) -} - -// TODO: Experiment with storing only the second word of event.node (unsafe.Pointer). -// Type can be recovered from the sole bit in typ. - -// Preorder visits all the nodes of the files supplied to New in -// depth-first order. It calls f(n) for each node n before it visits -// n's children. -// -// The complete traversal sequence is determined by ast.Inspect. -// The types argument, if non-empty, enables type-based filtering of -// events. The function f is called only for nodes whose type -// matches an element of the types slice. -func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { - // Because it avoids postorder calls to f, and the pruning - // check, Preorder is almost twice as fast as Nodes. The two - // features seem to contribute similar slowdowns (~1.4x each). - - // This function is equivalent to the PreorderSeq call below, - // but to avoid the additional dynamic call (which adds 13-35% - // to the benchmarks), we expand it out. - // - // in.PreorderSeq(types...)(func(n ast.Node) bool { - // f(n) - // return true - // }) - - mask := maskOf(types) - for i := int32(0); i < int32(len(in.events)); { - ev := in.events[i] - if ev.index > i { - // push - if ev.typ&mask != 0 { - f(ev.node) - } - pop := ev.index - if in.events[pop].typ&mask == 0 { - // Subtrees do not contain types: skip them and pop. - i = pop + 1 - continue - } - } - i++ - } -} - -// Nodes visits the nodes of the files supplied to New in depth-first -// order. It calls f(n, true) for each node n before it visits n's -// children. If f returns true, Nodes invokes f recursively for each -// of the non-nil children of the node, followed by a call of -// f(n, false). -// -// The complete traversal sequence is determined by ast.Inspect. -// The types argument, if non-empty, enables type-based filtering of -// events. The function f if is called only for nodes whose type -// matches an element of the types slice. -func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) { - mask := maskOf(types) - for i := int32(0); i < int32(len(in.events)); { - ev := in.events[i] - if ev.index > i { - // push - pop := ev.index - if ev.typ&mask != 0 { - if !f(ev.node, true) { - i = pop + 1 // jump to corresponding pop + 1 - continue - } - } - if in.events[pop].typ&mask == 0 { - // Subtrees do not contain types: skip them. - i = pop - continue - } - } else { - // pop - push := ev.index - if in.events[push].typ&mask != 0 { - f(ev.node, false) - } - } - i++ - } -} - -// WithStack visits nodes in a similar manner to Nodes, but it -// supplies each call to f an additional argument, the current -// traversal stack. The stack's first element is the outermost node, -// an *ast.File; its last is the innermost, n. -func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) { - mask := maskOf(types) - var stack []ast.Node - for i := int32(0); i < int32(len(in.events)); { - ev := in.events[i] - if ev.index > i { - // push - pop := ev.index - stack = append(stack, ev.node) - if ev.typ&mask != 0 { - if !f(ev.node, true, stack) { - i = pop + 1 - stack = stack[:len(stack)-1] - continue - } - } - if in.events[pop].typ&mask == 0 { - // Subtrees does not contain types: skip them. - i = pop - continue - } - } else { - // pop - push := ev.index - if in.events[push].typ&mask != 0 { - f(ev.node, false, stack) - } - stack = stack[:len(stack)-1] - } - i++ - } -} - -// traverse builds the table of events representing a traversal. -func traverse(files []*ast.File) []event { - // Preallocate approximate number of events - // based on source file extent of the declarations. - // (We use End-Pos not FileStart-FileEnd to neglect - // the effect of long doc comments.) - // This makes traverse faster by 4x (!). - var extent int - for _, f := range files { - extent += int(f.End() - f.Pos()) - } - // This estimate is based on the net/http package. - capacity := min(extent*33/100, 1e6) // impose some reasonable maximum (1M) - - v := &visitor{ - events: make([]event, 0, capacity), - stack: []item{{index: -1}}, // include an extra event so file nodes have a parent - } - for _, file := range files { - walk(v, edge.Invalid, -1, file) - } - return v.events -} - -type visitor struct { - events []event - stack []item -} - -type item struct { - index int32 // index of current node's push event - parentIndex int32 // index of parent node's push event - typAccum uint64 // accumulated type bits of current node's descendents - edgeKindAndIndex int32 // edge.Kind and index, bit packed -} - -func (v *visitor) push(ek edge.Kind, eindex int, node ast.Node) { - var ( - index = int32(len(v.events)) - parentIndex = v.stack[len(v.stack)-1].index - ) - v.events = append(v.events, event{ - node: node, - parent: parentIndex, - typ: typeOf(node), - index: 0, // (pop index is set later by visitor.pop) - }) - v.stack = append(v.stack, item{ - index: index, - parentIndex: parentIndex, - edgeKindAndIndex: packEdgeKindAndIndex(ek, eindex), - }) - - // 2B nodes ought to be enough for anyone! - if int32(len(v.events)) < 0 { - panic("event index exceeded int32") - } - - // 32M elements in an []ast.Node ought to be enough for anyone! - if ek2, eindex2 := unpackEdgeKindAndIndex(packEdgeKindAndIndex(ek, eindex)); ek2 != ek || eindex2 != eindex { - panic("Node slice index exceeded uint25") - } -} - -func (v *visitor) pop(node ast.Node) { - top := len(v.stack) - 1 - current := v.stack[top] - - push := &v.events[current.index] - parent := &v.stack[top-1] - - push.index = int32(len(v.events)) // make push event refer to pop - parent.typAccum |= current.typAccum | push.typ // accumulate type bits into parent - - v.stack = v.stack[:top] - - v.events = append(v.events, event{ - node: node, - typ: current.typAccum, - index: current.index, - parent: current.edgeKindAndIndex, // see [unpackEdgeKindAndIndex] - }) -} diff --git a/vendor/golang.org/x/tools/go/ast/inspector/iter.go b/vendor/golang.org/x/tools/go/ast/inspector/iter.go deleted file mode 100644 index c576dc70ac..0000000000 --- a/vendor/golang.org/x/tools/go/ast/inspector/iter.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.23 - -package inspector - -import ( - "go/ast" - "iter" -) - -// PreorderSeq returns an iterator that visits all the -// nodes of the files supplied to New in depth-first order. -// It visits each node n before n's children. -// The complete traversal sequence is determined by ast.Inspect. -// -// The types argument, if non-empty, enables type-based -// filtering of events: only nodes whose type matches an -// element of the types slice are included in the sequence. -func (in *Inspector) PreorderSeq(types ...ast.Node) iter.Seq[ast.Node] { - - // This implementation is identical to Preorder, - // except that it supports breaking out of the loop. - - return func(yield func(ast.Node) bool) { - mask := maskOf(types) - for i := int32(0); i < int32(len(in.events)); { - ev := in.events[i] - if ev.index > i { - // push - if ev.typ&mask != 0 { - if !yield(ev.node) { - break - } - } - pop := ev.index - if in.events[pop].typ&mask == 0 { - // Subtrees do not contain types: skip them and pop. - i = pop + 1 - continue - } - } - i++ - } - } -} - -// All[N] returns an iterator over all the nodes of type N. -// N must be a pointer-to-struct type that implements ast.Node. -// -// Example: -// -// for call := range All[*ast.CallExpr](in) { ... } -func All[N interface { - *S - ast.Node -}, S any](in *Inspector) iter.Seq[N] { - - // To avoid additional dynamic call overheads, - // we duplicate rather than call the logic of PreorderSeq. - - mask := typeOf((N)(nil)) - return func(yield func(N) bool) { - for i := int32(0); i < int32(len(in.events)); { - ev := in.events[i] - if ev.index > i { - // push - if ev.typ&mask != 0 { - if !yield(ev.node.(N)) { - break - } - } - pop := ev.index - if in.events[pop].typ&mask == 0 { - // Subtrees do not contain types: skip them and pop. - i = pop + 1 - continue - } - } - i++ - } - } -} diff --git a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go deleted file mode 100644 index e936c67c98..0000000000 --- a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package inspector - -// This file defines func typeOf(ast.Node) uint64. -// -// The initial map-based implementation was too slow; -// see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196 - -import ( - "go/ast" - "math" - - _ "unsafe" -) - -const ( - nArrayType = iota - nAssignStmt - nBadDecl - nBadExpr - nBadStmt - nBasicLit - nBinaryExpr - nBlockStmt - nBranchStmt - nCallExpr - nCaseClause - nChanType - nCommClause - nComment - nCommentGroup - nCompositeLit - nDeclStmt - nDeferStmt - nEllipsis - nEmptyStmt - nExprStmt - nField - nFieldList - nFile - nForStmt - nFuncDecl - nFuncLit - nFuncType - nGenDecl - nGoStmt - nIdent - nIfStmt - nImportSpec - nIncDecStmt - nIndexExpr - nIndexListExpr - nInterfaceType - nKeyValueExpr - nLabeledStmt - nMapType - nPackage - nParenExpr - nRangeStmt - nReturnStmt - nSelectStmt - nSelectorExpr - nSendStmt - nSliceExpr - nStarExpr - nStructType - nSwitchStmt - nTypeAssertExpr - nTypeSpec - nTypeSwitchStmt - nUnaryExpr - nValueSpec -) - -// typeOf returns a distinct single-bit value that represents the type of n. -// -// Various implementations were benchmarked with BenchmarkNewInspector: -// -// GOGC=off -// - type switch 4.9-5.5ms 2.1ms -// - binary search over a sorted list of types 5.5-5.9ms 2.5ms -// - linear scan, frequency-ordered list 5.9-6.1ms 2.7ms -// - linear scan, unordered list 6.4ms 2.7ms -// - hash table 6.5ms 3.1ms -// -// A perfect hash seemed like overkill. -// -// The compiler's switch statement is the clear winner -// as it produces a binary tree in code, -// with constant conditions and good branch prediction. -// (Sadly it is the most verbose in source code.) -// Binary search suffered from poor branch prediction. -func typeOf(n ast.Node) uint64 { - // Fast path: nearly half of all nodes are identifiers. - if _, ok := n.(*ast.Ident); ok { - return 1 << nIdent - } - - // These cases include all nodes encountered by ast.Inspect. - switch n.(type) { - case *ast.ArrayType: - return 1 << nArrayType - case *ast.AssignStmt: - return 1 << nAssignStmt - case *ast.BadDecl: - return 1 << nBadDecl - case *ast.BadExpr: - return 1 << nBadExpr - case *ast.BadStmt: - return 1 << nBadStmt - case *ast.BasicLit: - return 1 << nBasicLit - case *ast.BinaryExpr: - return 1 << nBinaryExpr - case *ast.BlockStmt: - return 1 << nBlockStmt - case *ast.BranchStmt: - return 1 << nBranchStmt - case *ast.CallExpr: - return 1 << nCallExpr - case *ast.CaseClause: - return 1 << nCaseClause - case *ast.ChanType: - return 1 << nChanType - case *ast.CommClause: - return 1 << nCommClause - case *ast.Comment: - return 1 << nComment - case *ast.CommentGroup: - return 1 << nCommentGroup - case *ast.CompositeLit: - return 1 << nCompositeLit - case *ast.DeclStmt: - return 1 << nDeclStmt - case *ast.DeferStmt: - return 1 << nDeferStmt - case *ast.Ellipsis: - return 1 << nEllipsis - case *ast.EmptyStmt: - return 1 << nEmptyStmt - case *ast.ExprStmt: - return 1 << nExprStmt - case *ast.Field: - return 1 << nField - case *ast.FieldList: - return 1 << nFieldList - case *ast.File: - return 1 << nFile - case *ast.ForStmt: - return 1 << nForStmt - case *ast.FuncDecl: - return 1 << nFuncDecl - case *ast.FuncLit: - return 1 << nFuncLit - case *ast.FuncType: - return 1 << nFuncType - case *ast.GenDecl: - return 1 << nGenDecl - case *ast.GoStmt: - return 1 << nGoStmt - case *ast.Ident: - return 1 << nIdent - case *ast.IfStmt: - return 1 << nIfStmt - case *ast.ImportSpec: - return 1 << nImportSpec - case *ast.IncDecStmt: - return 1 << nIncDecStmt - case *ast.IndexExpr: - return 1 << nIndexExpr - case *ast.IndexListExpr: - return 1 << nIndexListExpr - case *ast.InterfaceType: - return 1 << nInterfaceType - case *ast.KeyValueExpr: - return 1 << nKeyValueExpr - case *ast.LabeledStmt: - return 1 << nLabeledStmt - case *ast.MapType: - return 1 << nMapType - case *ast.Package: - return 1 << nPackage - case *ast.ParenExpr: - return 1 << nParenExpr - case *ast.RangeStmt: - return 1 << nRangeStmt - case *ast.ReturnStmt: - return 1 << nReturnStmt - case *ast.SelectStmt: - return 1 << nSelectStmt - case *ast.SelectorExpr: - return 1 << nSelectorExpr - case *ast.SendStmt: - return 1 << nSendStmt - case *ast.SliceExpr: - return 1 << nSliceExpr - case *ast.StarExpr: - return 1 << nStarExpr - case *ast.StructType: - return 1 << nStructType - case *ast.SwitchStmt: - return 1 << nSwitchStmt - case *ast.TypeAssertExpr: - return 1 << nTypeAssertExpr - case *ast.TypeSpec: - return 1 << nTypeSpec - case *ast.TypeSwitchStmt: - return 1 << nTypeSwitchStmt - case *ast.UnaryExpr: - return 1 << nUnaryExpr - case *ast.ValueSpec: - return 1 << nValueSpec - } - return 0 -} - -//go:linkname maskOf golang.org/x/tools/go/ast/inspector.maskOf -func maskOf(nodes []ast.Node) uint64 { - if len(nodes) == 0 { - return math.MaxUint64 // match all node types - } - var mask uint64 - for _, n := range nodes { - mask |= typeOf(n) - } - return mask -} diff --git a/vendor/golang.org/x/tools/go/ast/inspector/walk.go b/vendor/golang.org/x/tools/go/ast/inspector/walk.go deleted file mode 100644 index 5a42174a0a..0000000000 --- a/vendor/golang.org/x/tools/go/ast/inspector/walk.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2025 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package inspector - -// This file is a fork of ast.Inspect to reduce unnecessary dynamic -// calls and to gather edge information. -// -// Consistency with the original is ensured by TestInspectAllNodes. - -import ( - "fmt" - "go/ast" - - "golang.org/x/tools/internal/astutil/edge" -) - -func walkList[N ast.Node](v *visitor, ek edge.Kind, list []N) { - for i, node := range list { - walk(v, ek, i, node) - } -} - -func walk(v *visitor, ek edge.Kind, index int, node ast.Node) { - v.push(ek, index, node) - - // walk children - // (the order of the cases matches the order - // of the corresponding node types in ast.go) - switch n := node.(type) { - // Comments and fields - case *ast.Comment: - // nothing to do - - case *ast.CommentGroup: - walkList(v, edge.CommentGroup_List, n.List) - - case *ast.Field: - if n.Doc != nil { - walk(v, edge.Field_Doc, -1, n.Doc) - } - walkList(v, edge.Field_Names, n.Names) - if n.Type != nil { - walk(v, edge.Field_Type, -1, n.Type) - } - if n.Tag != nil { - walk(v, edge.Field_Tag, -1, n.Tag) - } - if n.Comment != nil { - walk(v, edge.Field_Comment, -1, n.Comment) - } - - case *ast.FieldList: - walkList(v, edge.FieldList_List, n.List) - - // Expressions - case *ast.BadExpr, *ast.Ident, *ast.BasicLit: - // nothing to do - - case *ast.Ellipsis: - if n.Elt != nil { - walk(v, edge.Ellipsis_Elt, -1, n.Elt) - } - - case *ast.FuncLit: - walk(v, edge.FuncLit_Type, -1, n.Type) - walk(v, edge.FuncLit_Body, -1, n.Body) - - case *ast.CompositeLit: - if n.Type != nil { - walk(v, edge.CompositeLit_Type, -1, n.Type) - } - walkList(v, edge.CompositeLit_Elts, n.Elts) - - case *ast.ParenExpr: - walk(v, edge.ParenExpr_X, -1, n.X) - - case *ast.SelectorExpr: - walk(v, edge.SelectorExpr_X, -1, n.X) - walk(v, edge.SelectorExpr_Sel, -1, n.Sel) - - case *ast.IndexExpr: - walk(v, edge.IndexExpr_X, -1, n.X) - walk(v, edge.IndexExpr_Index, -1, n.Index) - - case *ast.IndexListExpr: - walk(v, edge.IndexListExpr_X, -1, n.X) - walkList(v, edge.IndexListExpr_Indices, n.Indices) - - case *ast.SliceExpr: - walk(v, edge.SliceExpr_X, -1, n.X) - if n.Low != nil { - walk(v, edge.SliceExpr_Low, -1, n.Low) - } - if n.High != nil { - walk(v, edge.SliceExpr_High, -1, n.High) - } - if n.Max != nil { - walk(v, edge.SliceExpr_Max, -1, n.Max) - } - - case *ast.TypeAssertExpr: - walk(v, edge.TypeAssertExpr_X, -1, n.X) - if n.Type != nil { - walk(v, edge.TypeAssertExpr_Type, -1, n.Type) - } - - case *ast.CallExpr: - walk(v, edge.CallExpr_Fun, -1, n.Fun) - walkList(v, edge.CallExpr_Args, n.Args) - - case *ast.StarExpr: - walk(v, edge.StarExpr_X, -1, n.X) - - case *ast.UnaryExpr: - walk(v, edge.UnaryExpr_X, -1, n.X) - - case *ast.BinaryExpr: - walk(v, edge.BinaryExpr_X, -1, n.X) - walk(v, edge.BinaryExpr_Y, -1, n.Y) - - case *ast.KeyValueExpr: - walk(v, edge.KeyValueExpr_Key, -1, n.Key) - walk(v, edge.KeyValueExpr_Value, -1, n.Value) - - // Types - case *ast.ArrayType: - if n.Len != nil { - walk(v, edge.ArrayType_Len, -1, n.Len) - } - walk(v, edge.ArrayType_Elt, -1, n.Elt) - - case *ast.StructType: - walk(v, edge.StructType_Fields, -1, n.Fields) - - case *ast.FuncType: - if n.TypeParams != nil { - walk(v, edge.FuncType_TypeParams, -1, n.TypeParams) - } - if n.Params != nil { - walk(v, edge.FuncType_Params, -1, n.Params) - } - if n.Results != nil { - walk(v, edge.FuncType_Results, -1, n.Results) - } - - case *ast.InterfaceType: - walk(v, edge.InterfaceType_Methods, -1, n.Methods) - - case *ast.MapType: - walk(v, edge.MapType_Key, -1, n.Key) - walk(v, edge.MapType_Value, -1, n.Value) - - case *ast.ChanType: - walk(v, edge.ChanType_Value, -1, n.Value) - - // Statements - case *ast.BadStmt: - // nothing to do - - case *ast.DeclStmt: - walk(v, edge.DeclStmt_Decl, -1, n.Decl) - - case *ast.EmptyStmt: - // nothing to do - - case *ast.LabeledStmt: - walk(v, edge.LabeledStmt_Label, -1, n.Label) - walk(v, edge.LabeledStmt_Stmt, -1, n.Stmt) - - case *ast.ExprStmt: - walk(v, edge.ExprStmt_X, -1, n.X) - - case *ast.SendStmt: - walk(v, edge.SendStmt_Chan, -1, n.Chan) - walk(v, edge.SendStmt_Value, -1, n.Value) - - case *ast.IncDecStmt: - walk(v, edge.IncDecStmt_X, -1, n.X) - - case *ast.AssignStmt: - walkList(v, edge.AssignStmt_Lhs, n.Lhs) - walkList(v, edge.AssignStmt_Rhs, n.Rhs) - - case *ast.GoStmt: - walk(v, edge.GoStmt_Call, -1, n.Call) - - case *ast.DeferStmt: - walk(v, edge.DeferStmt_Call, -1, n.Call) - - case *ast.ReturnStmt: - walkList(v, edge.ReturnStmt_Results, n.Results) - - case *ast.BranchStmt: - if n.Label != nil { - walk(v, edge.BranchStmt_Label, -1, n.Label) - } - - case *ast.BlockStmt: - walkList(v, edge.BlockStmt_List, n.List) - - case *ast.IfStmt: - if n.Init != nil { - walk(v, edge.IfStmt_Init, -1, n.Init) - } - walk(v, edge.IfStmt_Cond, -1, n.Cond) - walk(v, edge.IfStmt_Body, -1, n.Body) - if n.Else != nil { - walk(v, edge.IfStmt_Else, -1, n.Else) - } - - case *ast.CaseClause: - walkList(v, edge.CaseClause_List, n.List) - walkList(v, edge.CaseClause_Body, n.Body) - - case *ast.SwitchStmt: - if n.Init != nil { - walk(v, edge.SwitchStmt_Init, -1, n.Init) - } - if n.Tag != nil { - walk(v, edge.SwitchStmt_Tag, -1, n.Tag) - } - walk(v, edge.SwitchStmt_Body, -1, n.Body) - - case *ast.TypeSwitchStmt: - if n.Init != nil { - walk(v, edge.TypeSwitchStmt_Init, -1, n.Init) - } - walk(v, edge.TypeSwitchStmt_Assign, -1, n.Assign) - walk(v, edge.TypeSwitchStmt_Body, -1, n.Body) - - case *ast.CommClause: - if n.Comm != nil { - walk(v, edge.CommClause_Comm, -1, n.Comm) - } - walkList(v, edge.CommClause_Body, n.Body) - - case *ast.SelectStmt: - walk(v, edge.SelectStmt_Body, -1, n.Body) - - case *ast.ForStmt: - if n.Init != nil { - walk(v, edge.ForStmt_Init, -1, n.Init) - } - if n.Cond != nil { - walk(v, edge.ForStmt_Cond, -1, n.Cond) - } - if n.Post != nil { - walk(v, edge.ForStmt_Post, -1, n.Post) - } - walk(v, edge.ForStmt_Body, -1, n.Body) - - case *ast.RangeStmt: - if n.Key != nil { - walk(v, edge.RangeStmt_Key, -1, n.Key) - } - if n.Value != nil { - walk(v, edge.RangeStmt_Value, -1, n.Value) - } - walk(v, edge.RangeStmt_X, -1, n.X) - walk(v, edge.RangeStmt_Body, -1, n.Body) - - // Declarations - case *ast.ImportSpec: - if n.Doc != nil { - walk(v, edge.ImportSpec_Doc, -1, n.Doc) - } - if n.Name != nil { - walk(v, edge.ImportSpec_Name, -1, n.Name) - } - walk(v, edge.ImportSpec_Path, -1, n.Path) - if n.Comment != nil { - walk(v, edge.ImportSpec_Comment, -1, n.Comment) - } - - case *ast.ValueSpec: - if n.Doc != nil { - walk(v, edge.ValueSpec_Doc, -1, n.Doc) - } - walkList(v, edge.ValueSpec_Names, n.Names) - if n.Type != nil { - walk(v, edge.ValueSpec_Type, -1, n.Type) - } - walkList(v, edge.ValueSpec_Values, n.Values) - if n.Comment != nil { - walk(v, edge.ValueSpec_Comment, -1, n.Comment) - } - - case *ast.TypeSpec: - if n.Doc != nil { - walk(v, edge.TypeSpec_Doc, -1, n.Doc) - } - walk(v, edge.TypeSpec_Name, -1, n.Name) - if n.TypeParams != nil { - walk(v, edge.TypeSpec_TypeParams, -1, n.TypeParams) - } - walk(v, edge.TypeSpec_Type, -1, n.Type) - if n.Comment != nil { - walk(v, edge.TypeSpec_Comment, -1, n.Comment) - } - - case *ast.BadDecl: - // nothing to do - - case *ast.GenDecl: - if n.Doc != nil { - walk(v, edge.GenDecl_Doc, -1, n.Doc) - } - walkList(v, edge.GenDecl_Specs, n.Specs) - - case *ast.FuncDecl: - if n.Doc != nil { - walk(v, edge.FuncDecl_Doc, -1, n.Doc) - } - if n.Recv != nil { - walk(v, edge.FuncDecl_Recv, -1, n.Recv) - } - walk(v, edge.FuncDecl_Name, -1, n.Name) - walk(v, edge.FuncDecl_Type, -1, n.Type) - if n.Body != nil { - walk(v, edge.FuncDecl_Body, -1, n.Body) - } - - case *ast.File: - if n.Doc != nil { - walk(v, edge.File_Doc, -1, n.Doc) - } - walk(v, edge.File_Name, -1, n.Name) - walkList(v, edge.File_Decls, n.Decls) - // don't walk n.Comments - they have been - // visited already through the individual - // nodes - - default: - // (includes *ast.Package) - panic(fmt.Sprintf("Walk: unexpected node type %T", n)) - } - - v.pop(node) -} diff --git a/vendor/golang.org/x/tools/internal/astutil/edge/edge.go b/vendor/golang.org/x/tools/internal/astutil/edge/edge.go deleted file mode 100644 index 4f6ccfd6e5..0000000000 --- a/vendor/golang.org/x/tools/internal/astutil/edge/edge.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2025 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package edge defines identifiers for each field of an ast.Node -// struct type that refers to another Node. -package edge - -import ( - "fmt" - "go/ast" - "reflect" -) - -// A Kind describes a field of an ast.Node struct. -type Kind uint8 - -// String returns a description of the edge kind. -func (k Kind) String() string { - if k == Invalid { - return "" - } - info := fieldInfos[k] - return fmt.Sprintf("%v.%s", info.nodeType.Elem().Name(), info.name) -} - -// NodeType returns the pointer-to-struct type of the ast.Node implementation. -func (k Kind) NodeType() reflect.Type { return fieldInfos[k].nodeType } - -// FieldName returns the name of the field. -func (k Kind) FieldName() string { return fieldInfos[k].name } - -// FieldType returns the declared type of the field. -func (k Kind) FieldType() reflect.Type { return fieldInfos[k].fieldType } - -// Get returns the direct child of n identified by (k, idx). -// n's type must match k.NodeType(). -// idx must be a valid slice index, or -1 for a non-slice. -func (k Kind) Get(n ast.Node, idx int) ast.Node { - if k.NodeType() != reflect.TypeOf(n) { - panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n)) - } - v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index) - if idx != -1 { - v = v.Index(idx) // asserts valid index - } else { - // (The type assertion below asserts that v is not a slice.) - } - return v.Interface().(ast.Node) // may be nil -} - -const ( - Invalid Kind = iota // for nodes at the root of the traversal - - // Kinds are sorted alphabetically. - // Numbering is not stable. - // Each is named Type_Field, where Type is the - // ast.Node struct type and Field is the name of the field - - ArrayType_Elt - ArrayType_Len - AssignStmt_Lhs - AssignStmt_Rhs - BinaryExpr_X - BinaryExpr_Y - BlockStmt_List - BranchStmt_Label - CallExpr_Args - CallExpr_Fun - CaseClause_Body - CaseClause_List - ChanType_Value - CommClause_Body - CommClause_Comm - CommentGroup_List - CompositeLit_Elts - CompositeLit_Type - DeclStmt_Decl - DeferStmt_Call - Ellipsis_Elt - ExprStmt_X - FieldList_List - Field_Comment - Field_Doc - Field_Names - Field_Tag - Field_Type - File_Decls - File_Doc - File_Name - ForStmt_Body - ForStmt_Cond - ForStmt_Init - ForStmt_Post - FuncDecl_Body - FuncDecl_Doc - FuncDecl_Name - FuncDecl_Recv - FuncDecl_Type - FuncLit_Body - FuncLit_Type - FuncType_Params - FuncType_Results - FuncType_TypeParams - GenDecl_Doc - GenDecl_Specs - GoStmt_Call - IfStmt_Body - IfStmt_Cond - IfStmt_Else - IfStmt_Init - ImportSpec_Comment - ImportSpec_Doc - ImportSpec_Name - ImportSpec_Path - IncDecStmt_X - IndexExpr_Index - IndexExpr_X - IndexListExpr_Indices - IndexListExpr_X - InterfaceType_Methods - KeyValueExpr_Key - KeyValueExpr_Value - LabeledStmt_Label - LabeledStmt_Stmt - MapType_Key - MapType_Value - ParenExpr_X - RangeStmt_Body - RangeStmt_Key - RangeStmt_Value - RangeStmt_X - ReturnStmt_Results - SelectStmt_Body - SelectorExpr_Sel - SelectorExpr_X - SendStmt_Chan - SendStmt_Value - SliceExpr_High - SliceExpr_Low - SliceExpr_Max - SliceExpr_X - StarExpr_X - StructType_Fields - SwitchStmt_Body - SwitchStmt_Init - SwitchStmt_Tag - TypeAssertExpr_Type - TypeAssertExpr_X - TypeSpec_Comment - TypeSpec_Doc - TypeSpec_Name - TypeSpec_Type - TypeSpec_TypeParams - TypeSwitchStmt_Assign - TypeSwitchStmt_Body - TypeSwitchStmt_Init - UnaryExpr_X - ValueSpec_Comment - ValueSpec_Doc - ValueSpec_Names - ValueSpec_Type - ValueSpec_Values - - maxKind -) - -// Assert that the encoding fits in 7 bits, -// as the inspector relies on this. -// (We are currently at 104.) -var _ = [1 << 7]struct{}{}[maxKind] - -type fieldInfo struct { - nodeType reflect.Type // pointer-to-struct type of ast.Node implementation - name string - index int - fieldType reflect.Type -} - -func info[N ast.Node](fieldName string) fieldInfo { - nodePtrType := reflect.TypeFor[N]() - f, ok := nodePtrType.Elem().FieldByName(fieldName) - if !ok { - panic(fieldName) - } - return fieldInfo{nodePtrType, fieldName, f.Index[0], f.Type} -} - -var fieldInfos = [...]fieldInfo{ - Invalid: {}, - ArrayType_Elt: info[*ast.ArrayType]("Elt"), - ArrayType_Len: info[*ast.ArrayType]("Len"), - AssignStmt_Lhs: info[*ast.AssignStmt]("Lhs"), - AssignStmt_Rhs: info[*ast.AssignStmt]("Rhs"), - BinaryExpr_X: info[*ast.BinaryExpr]("X"), - BinaryExpr_Y: info[*ast.BinaryExpr]("Y"), - BlockStmt_List: info[*ast.BlockStmt]("List"), - BranchStmt_Label: info[*ast.BranchStmt]("Label"), - CallExpr_Args: info[*ast.CallExpr]("Args"), - CallExpr_Fun: info[*ast.CallExpr]("Fun"), - CaseClause_Body: info[*ast.CaseClause]("Body"), - CaseClause_List: info[*ast.CaseClause]("List"), - ChanType_Value: info[*ast.ChanType]("Value"), - CommClause_Body: info[*ast.CommClause]("Body"), - CommClause_Comm: info[*ast.CommClause]("Comm"), - CommentGroup_List: info[*ast.CommentGroup]("List"), - CompositeLit_Elts: info[*ast.CompositeLit]("Elts"), - CompositeLit_Type: info[*ast.CompositeLit]("Type"), - DeclStmt_Decl: info[*ast.DeclStmt]("Decl"), - DeferStmt_Call: info[*ast.DeferStmt]("Call"), - Ellipsis_Elt: info[*ast.Ellipsis]("Elt"), - ExprStmt_X: info[*ast.ExprStmt]("X"), - FieldList_List: info[*ast.FieldList]("List"), - Field_Comment: info[*ast.Field]("Comment"), - Field_Doc: info[*ast.Field]("Doc"), - Field_Names: info[*ast.Field]("Names"), - Field_Tag: info[*ast.Field]("Tag"), - Field_Type: info[*ast.Field]("Type"), - File_Decls: info[*ast.File]("Decls"), - File_Doc: info[*ast.File]("Doc"), - File_Name: info[*ast.File]("Name"), - ForStmt_Body: info[*ast.ForStmt]("Body"), - ForStmt_Cond: info[*ast.ForStmt]("Cond"), - ForStmt_Init: info[*ast.ForStmt]("Init"), - ForStmt_Post: info[*ast.ForStmt]("Post"), - FuncDecl_Body: info[*ast.FuncDecl]("Body"), - FuncDecl_Doc: info[*ast.FuncDecl]("Doc"), - FuncDecl_Name: info[*ast.FuncDecl]("Name"), - FuncDecl_Recv: info[*ast.FuncDecl]("Recv"), - FuncDecl_Type: info[*ast.FuncDecl]("Type"), - FuncLit_Body: info[*ast.FuncLit]("Body"), - FuncLit_Type: info[*ast.FuncLit]("Type"), - FuncType_Params: info[*ast.FuncType]("Params"), - FuncType_Results: info[*ast.FuncType]("Results"), - FuncType_TypeParams: info[*ast.FuncType]("TypeParams"), - GenDecl_Doc: info[*ast.GenDecl]("Doc"), - GenDecl_Specs: info[*ast.GenDecl]("Specs"), - GoStmt_Call: info[*ast.GoStmt]("Call"), - IfStmt_Body: info[*ast.IfStmt]("Body"), - IfStmt_Cond: info[*ast.IfStmt]("Cond"), - IfStmt_Else: info[*ast.IfStmt]("Else"), - IfStmt_Init: info[*ast.IfStmt]("Init"), - ImportSpec_Comment: info[*ast.ImportSpec]("Comment"), - ImportSpec_Doc: info[*ast.ImportSpec]("Doc"), - ImportSpec_Name: info[*ast.ImportSpec]("Name"), - ImportSpec_Path: info[*ast.ImportSpec]("Path"), - IncDecStmt_X: info[*ast.IncDecStmt]("X"), - IndexExpr_Index: info[*ast.IndexExpr]("Index"), - IndexExpr_X: info[*ast.IndexExpr]("X"), - IndexListExpr_Indices: info[*ast.IndexListExpr]("Indices"), - IndexListExpr_X: info[*ast.IndexListExpr]("X"), - InterfaceType_Methods: info[*ast.InterfaceType]("Methods"), - KeyValueExpr_Key: info[*ast.KeyValueExpr]("Key"), - KeyValueExpr_Value: info[*ast.KeyValueExpr]("Value"), - LabeledStmt_Label: info[*ast.LabeledStmt]("Label"), - LabeledStmt_Stmt: info[*ast.LabeledStmt]("Stmt"), - MapType_Key: info[*ast.MapType]("Key"), - MapType_Value: info[*ast.MapType]("Value"), - ParenExpr_X: info[*ast.ParenExpr]("X"), - RangeStmt_Body: info[*ast.RangeStmt]("Body"), - RangeStmt_Key: info[*ast.RangeStmt]("Key"), - RangeStmt_Value: info[*ast.RangeStmt]("Value"), - RangeStmt_X: info[*ast.RangeStmt]("X"), - ReturnStmt_Results: info[*ast.ReturnStmt]("Results"), - SelectStmt_Body: info[*ast.SelectStmt]("Body"), - SelectorExpr_Sel: info[*ast.SelectorExpr]("Sel"), - SelectorExpr_X: info[*ast.SelectorExpr]("X"), - SendStmt_Chan: info[*ast.SendStmt]("Chan"), - SendStmt_Value: info[*ast.SendStmt]("Value"), - SliceExpr_High: info[*ast.SliceExpr]("High"), - SliceExpr_Low: info[*ast.SliceExpr]("Low"), - SliceExpr_Max: info[*ast.SliceExpr]("Max"), - SliceExpr_X: info[*ast.SliceExpr]("X"), - StarExpr_X: info[*ast.StarExpr]("X"), - StructType_Fields: info[*ast.StructType]("Fields"), - SwitchStmt_Body: info[*ast.SwitchStmt]("Body"), - SwitchStmt_Init: info[*ast.SwitchStmt]("Init"), - SwitchStmt_Tag: info[*ast.SwitchStmt]("Tag"), - TypeAssertExpr_Type: info[*ast.TypeAssertExpr]("Type"), - TypeAssertExpr_X: info[*ast.TypeAssertExpr]("X"), - TypeSpec_Comment: info[*ast.TypeSpec]("Comment"), - TypeSpec_Doc: info[*ast.TypeSpec]("Doc"), - TypeSpec_Name: info[*ast.TypeSpec]("Name"), - TypeSpec_Type: info[*ast.TypeSpec]("Type"), - TypeSpec_TypeParams: info[*ast.TypeSpec]("TypeParams"), - TypeSwitchStmt_Assign: info[*ast.TypeSwitchStmt]("Assign"), - TypeSwitchStmt_Body: info[*ast.TypeSwitchStmt]("Body"), - TypeSwitchStmt_Init: info[*ast.TypeSwitchStmt]("Init"), - UnaryExpr_X: info[*ast.UnaryExpr]("X"), - ValueSpec_Comment: info[*ast.ValueSpec]("Comment"), - ValueSpec_Doc: info[*ast.ValueSpec]("Doc"), - ValueSpec_Names: info[*ast.ValueSpec]("Names"), - ValueSpec_Type: info[*ast.ValueSpec]("Type"), - ValueSpec_Values: info[*ast.ValueSpec]("Values"), -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 740888393b..a1bce3989d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -19,9 +19,6 @@ github.com/dchest/safefile ## explicit; go 1.17 github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify/internal -# github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 -## explicit; go 1.13 -github.com/go-task/slim-sprig # github.com/golang/protobuf v1.5.3 ## explicit; go 1.9 github.com/golang/protobuf/proto @@ -29,9 +26,6 @@ github.com/golang/protobuf/ptypes github.com/golang/protobuf/ptypes/any github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/timestamp -# github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 -## explicit; go 1.14 -github.com/google/pprof/profile # github.com/gorilla/websocket v1.5.3 ## explicit; go 1.12 github.com/gorilla/websocket @@ -81,24 +75,6 @@ github.com/lifenjoiner/dhcpdns # github.com/miekg/dns v1.1.66 ## explicit; go 1.23.0 github.com/miekg/dns -# github.com/onsi/ginkgo/v2 v2.9.5 -## explicit; go 1.18 -github.com/onsi/ginkgo/v2/config -github.com/onsi/ginkgo/v2/formatter -github.com/onsi/ginkgo/v2/ginkgo -github.com/onsi/ginkgo/v2/ginkgo/build -github.com/onsi/ginkgo/v2/ginkgo/command -github.com/onsi/ginkgo/v2/ginkgo/generators -github.com/onsi/ginkgo/v2/ginkgo/internal -github.com/onsi/ginkgo/v2/ginkgo/labels -github.com/onsi/ginkgo/v2/ginkgo/outline -github.com/onsi/ginkgo/v2/ginkgo/run -github.com/onsi/ginkgo/v2/ginkgo/unfocus -github.com/onsi/ginkgo/v2/ginkgo/watch -github.com/onsi/ginkgo/v2/internal/interrupt_handler -github.com/onsi/ginkgo/v2/internal/parallel_support -github.com/onsi/ginkgo/v2/reporters -github.com/onsi/ginkgo/v2/types # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors @@ -114,7 +90,7 @@ github.com/powerman/deepequal # github.com/quic-go/qpack v0.5.1 ## explicit; go 1.22 github.com/quic-go/qpack -# github.com/quic-go/quic-go v0.52.0 +# github.com/quic-go/quic-go v0.53.0 ## explicit; go 1.23 github.com/quic-go/quic-go github.com/quic-go/quic-go/http3 @@ -193,14 +169,12 @@ golang.org/x/text/unicode/norm # golang.org/x/tools v0.33.0 ## explicit; go 1.23.0 golang.org/x/tools/go/ast/astutil -golang.org/x/tools/go/ast/inspector golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/packages golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/imports golang.org/x/tools/internal/aliases -golang.org/x/tools/internal/astutil/edge golang.org/x/tools/internal/event golang.org/x/tools/internal/event/core golang.org/x/tools/internal/event/keys