From 5f1db863b796eda7c2ee30517829436a3386dfc6 Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:17:28 +0300 Subject: [PATCH 01/11] test: add external test account api --- examples/go.mod | 12 +- examples/go.sum | 6 + go.mod | 15 +- go.sum | 33 +- testutil/.ogen.yml | 6 + testutil/generate.go | 3 + testutil/tgacc.go | 133 +++ testutil/tgacc.openapi.yaml | 213 +++++ testutil/tgacc/oas_cfg_gen.go | 143 ++++ testutil/tgacc/oas_client_gen.go | 478 +++++++++++ testutil/tgacc/oas_json_gen.go | 850 ++++++++++++++++++++ testutil/tgacc/oas_operations_gen.go | 13 + testutil/tgacc/oas_parameters_gen.go | 18 + testutil/tgacc/oas_request_encoders_gen.go | 26 + testutil/tgacc/oas_response_decoders_gen.go | 369 +++++++++ testutil/tgacc/oas_schemas_gen.go | 440 ++++++++++ testutil/tgacc/oas_security_gen.go | 25 + testutil/tgacc/oas_validators_gen.go | 189 +++++ testutil/tgacc_test.go | 23 + testutil/tools.go | 13 + 20 files changed, 2992 insertions(+), 16 deletions(-) create mode 100644 testutil/.ogen.yml create mode 100644 testutil/generate.go create mode 100644 testutil/tgacc.go create mode 100644 testutil/tgacc.openapi.yaml create mode 100644 testutil/tgacc/oas_cfg_gen.go create mode 100644 testutil/tgacc/oas_client_gen.go create mode 100644 testutil/tgacc/oas_json_gen.go create mode 100644 testutil/tgacc/oas_operations_gen.go create mode 100644 testutil/tgacc/oas_parameters_gen.go create mode 100644 testutil/tgacc/oas_request_encoders_gen.go create mode 100644 testutil/tgacc/oas_response_decoders_gen.go create mode 100644 testutil/tgacc/oas_schemas_gen.go create mode 100644 testutil/tgacc/oas_security_gen.go create mode 100644 testutil/tgacc/oas_validators_gen.go create mode 100644 testutil/tgacc_test.go create mode 100644 testutil/tools.go diff --git a/examples/go.mod b/examples/go.mod index 1c565b69c..fc0582132 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -11,8 +11,8 @@ require ( go.etcd.io/bbolt v1.3.9 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.9.0 - golang.org/x/term v0.26.0 + golang.org/x/sync v0.10.0 + golang.org/x/term v0.27.0 golang.org/x/time v0.5.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -47,11 +47,11 @@ require ( go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.29.0 // indirect + golang.org/x/crypto v0.30.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/net v0.32.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.33.0 // indirect nhooyr.io/websocket v1.8.17 // indirect rsc.io/qr v0.2.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index b75898bc0..48423dd05 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -99,6 +99,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -109,23 +110,28 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/go.mod b/go.mod index 390b9362e..ce411a34a 100644 --- a/go.mod +++ b/go.mod @@ -9,15 +9,18 @@ require ( github.com/go-faster/jx v1.1.0 github.com/go-faster/xor v1.0.0 github.com/go-openapi/inflect v0.21.0 + github.com/google/uuid v1.6.0 github.com/gotd/getdoc v0.44.0 github.com/gotd/ige v0.2.2 github.com/gotd/neo v0.1.5 github.com/gotd/tl v0.4.0 github.com/k0kubun/pp/v3 v3.4.1 github.com/klauspost/compress v1.17.11 + github.com/ogen-go/ogen v1.8.1 github.com/rogpeppe/go-internal v1.13.1 github.com/stretchr/testify v1.10.0 go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel/metric v1.32.0 go.opentelemetry.io/otel/trace v1.32.0 go.uber.org/atomic v1.11.0 go.uber.org/multierr v1.11.0 @@ -36,15 +39,21 @@ require ( github.com/andybalholm/cascadia v1.3.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/kr/pretty v0.3.1 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 902582852..a27edb4c8 100644 --- a/go.sum +++ b/go.sum @@ -8,10 +8,15 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= @@ -19,10 +24,19 @@ github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gotd/getdoc v0.44.0 h1:hSJzDY313wysMqmu6+sWg4pbKc4nJF1/316lxjmrPKk= github.com/gotd/getdoc v0.44.0/go.mod h1:tPqC2xq2IHhcxvmhdRfTA4ZK0YQKtJtbyZgbQcSuAXI= github.com/gotd/ige v0.2.2 h1:XQ9dJZwBfDnOGSTxKXBGP4gMud3Qku2ekScRjDWWfEk= @@ -36,7 +50,6 @@ github.com/k0kubun/pp/v3 v3.4.1/go.mod h1:+SiNiqKnBfw1Nkj82Lh5bIeKQOAkPy6Xw9CAZU github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -45,13 +58,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ogen-go/ogen v1.8.1 h1:7TZ+oIeLkcBiyl0qu0fHPrFUrGWDj3Fi/zKSWg2i2Tg= +github.com/ogen-go/ogen v1.8.1/go.mod h1:2ShRm6u/nXUHuwdVKv2SeaG8enBKPKAE3kSbHwwFh6o= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= @@ -70,6 +84,8 @@ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -86,8 +102,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20230116083435-1de6713980de h1:DBWn//IJw30uYCgERoxCg84hWtA97F4wMiKOIh00Uf0= -golang.org/x/exp v0.0.0-20230116083435-1de6713980de/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= @@ -112,6 +128,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -139,6 +156,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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/testutil/.ogen.yml b/testutil/.ogen.yml new file mode 100644 index 000000000..186849c98 --- /dev/null +++ b/testutil/.ogen.yml @@ -0,0 +1,6 @@ +generator: + features: + enable: + - "ogen/otel" + disable: + - "paths/server" diff --git a/testutil/generate.go b/testutil/generate.go new file mode 100644 index 000000000..31b9ed134 --- /dev/null +++ b/testutil/generate.go @@ -0,0 +1,3 @@ +package testutil + +//go:generate go run -mod=mod github.com/ogen-go/ogen/cmd/ogen --target tgacc --package tgacc --clean tgacc.openapi.yaml diff --git a/testutil/tgacc.go b/testutil/tgacc.go new file mode 100644 index 000000000..1af9205a0 --- /dev/null +++ b/testutil/tgacc.go @@ -0,0 +1,133 @@ +package testutil + +import ( + "context" + "os" + "strconv" + "time" + + "github.com/cenkalti/backoff/v4" + "github.com/go-faster/errors" + "github.com/google/uuid" + + "github.com/gotd/td/telegram/auth" + "github.com/gotd/td/testutil/tgacc" + "github.com/gotd/td/tg" +) + +// TestAccountManager is external test account manager. +type TestAccountManager struct { + client *tgacc.Client +} + +func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) { + jobID := os.Getenv("GITHUB_JOB_ID") + if jobID == "" { + return nil, errors.New("GITHUB_JOB_ID is empty") + } + runID, _ := strconv.ParseInt(os.Getenv("GITHUB_RUN_ID"), 10, 64) + if runID == 0 { + return nil, errors.New("GITHUB_RUN_ID is empty") + } + attempt, _ := strconv.Atoi(os.Getenv("GITHUB_RUN_ATTEMPT")) + res, err := t.client.AcquireTelegramAccount(ctx, &tgacc.AcquireTelegramAccountReq{ + RepoOwner: "gotd", + RepoName: "td", + Job: jobID, + RunID: runID, + RunAttempt: attempt, + }) + if err != nil { + return nil, errors.Wrap(err, "acquire account") + } + + phone := string(res.AccountID) + + return &TestAccount{ + Phone: phone, + AuthFlow: &codeAuth{ + phone: phone, + client: t.client, + }, + + token: res.Token, + client: t.client, + }, nil +} + +type ghSecuritySource struct{} + +func (s ghSecuritySource) TokenAuth(ctx context.Context, operationName tgacc.OperationName) (tgacc.TokenAuth, error) { + return tgacc.TokenAuth{ + APIKey: os.Getenv("GITHUB_TOKEN"), + }, nil +} + +type TestAccount struct { + Phone string + AuthFlow auth.UserAuthenticator + + token uuid.UUID + client *tgacc.Client +} + +// Close releases telegram account. +func (t TestAccount) Close() error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + return t.client.HeartbeatTelegramAccount(ctx, tgacc.HeartbeatTelegramAccountParams{ + Token: t.token, + Forget: tgacc.NewOptBool(true), + }) +} + +// codeAuth implements auth.UserAuthenticator prompting the external account +// manager. +type codeAuth struct { + phone string + token uuid.UUID + client *tgacc.Client +} + +func (codeAuth) SignUp(ctx context.Context) (auth.UserInfo, error) { + return auth.UserInfo{}, errors.New("not implemented") +} + +func (codeAuth) AcceptTermsOfService(ctx context.Context, tos tg.HelpTermsOfService) error { + return &auth.SignUpRequired{TermsOfService: tos} +} + +func (a codeAuth) Phone(_ context.Context) (string, error) { + return a.phone, nil +} + +func (codeAuth) Password(_ context.Context) (string, error) { + return "", errors.New("password not supported") +} + +func (a codeAuth) Code(ctx context.Context, sentCode *tg.AuthSentCode) (string, error) { + bo := backoff.NewExponentialBackOff() + bo.MaxElapsedTime = time.Minute + bo.MaxInterval = time.Second + + return backoff.RetryWithData(func() (string, error) { + res, err := a.client.ReceiveTelegramCode(ctx, tgacc.ReceiveTelegramCodeParams{ + Token: a.token, + }) + if err != nil { + return "", err + } + if res.Code.Value == "" { + return "", errors.New("no code") + } + return res.Code.Value, err + }, bo) +} + +func NewTestAccountManager() (*TestAccountManager, error) { + client, err := tgacc.NewClient("https://bot.gotd.dev", ghSecuritySource{}) + if err != nil { + return nil, errors.Wrap(err, "create client") + } + return &TestAccountManager{client: client}, nil +} diff --git a/testutil/tgacc.openapi.yaml b/testutil/tgacc.openapi.yaml new file mode 100644 index 000000000..b14079329 --- /dev/null +++ b/testutil/tgacc.openapi.yaml @@ -0,0 +1,213 @@ +openapi: 3.0.0 +info: + title: gotd bot api + description: gotd bot api + version: 1.0.0 +servers: + - url: 'http://localhost:8080' +paths: + /api/health: + get: + operationId: "getHealth" + description: "get health" + responses: + 200: + description: Health + content: + "application/json": + schema: + $ref: "#/components/schemas/Health" + default: + $ref: "#/components/responses/Error" + /api/telegram/account/heartbeat/{token}: + get: + operationId: "heartbeatTelegramAccount" + description: "heartbeat telegram account" + parameters: + - name: token + in: path + required: true + schema: + type: string + format: uuid + - name: forget + in: query + required: false + schema: + type: boolean + responses: + 200: + description: "Telegram account heartbeat" + default: + $ref: "#/components/responses/Error" + /api/telegram/code/receive/{token}: + get: + operationId: "receiveTelegramCode" + description: "receive telegram code" + parameters: + - name: token + in: path + required: true + schema: + type: string + format: uuid + responses: + 200: + description: "Telegram code received" + content: + "application/json": + schema: + type: object + properties: + code: + type: string + description: "Code" + example: "12345" + pattern: "^[0-9]{3,6}$" + default: + $ref: "#/components/responses/Error" + /api/telegram/account/acquire: + post: + security: + - tokenAuth: [] + operationId: "acquireTelegramAccount" + description: "acquire telegram account" + requestBody: + required: true + description: Info about current github workflow job + content: + application/json: + schema: + type: object + required: + - repo_owner + - repo_name + - commit_sha + - job + - run_id + - run_attempt + properties: + repo_owner: + type: string + description: "Repository owner" + example: "owner" + repo_name: + type: string + description: "Repository name" + example: "repo" + job: + type: string + description: "Job ID" + run_id: + type: integer + format: int64 + run_attempt: + type: integer + responses: + 200: + description: "Telegram account acquired" + content: + "application/json": + schema: + type: object + required: + - account_id + - token + properties: + account_id: + $ref: "#/components/schemas/TelegramAccountID" + token: + type: string + description: "Access token" + format: uuid + default: + $ref: "#/components/responses/Error" +components: + parameters: + TelegramAccountID: + name: id + in: path + required: true + schema: + $ref: "#/components/schemas/TelegramAccountID" + securitySchemes: + tokenAuth: + type: apiKey + in: header + name: Token + schemas: + TelegramAccountID: + type: string + pattern: "^[0-9]{7,15}$" + example: 71234567890 + # Error-related schemas. + TraceID: + type: string + description: W3C trace-id + pattern: "[[:xdigit:]]{32}" + example: 0af7651916cd43dd8448eb211c80319c + externalDocs: + url: "https://www.w3.org/TR/trace-context/#trace-id" + description: "W3C Trace Context specification" + SpanID: + type: string + description: W3C parent-id (span) + pattern: "[[:xdigit:]]{16}" + example: b7ad6b7169203331 + externalDocs: + url: "https://www.w3.org/TR/trace-context/#parent-id" + description: "W3C Trace Context specification" + Error: + title: Structured error + description: Error occurred while processing request + externalDocs: + url: "https://pfm.pages.gitlab.corp.mail.ru/docs/dev/spec/v2/errors" + description: "Structured error specification" + type: object + required: + - error_message + - body + properties: + error_message: + type: string + description: "Human-readable error message" + example: "Something went wrong" + trace_id: + $ref: "#/components/schemas/TraceID" + span_id: + $ref: "#/components/schemas/SpanID" + + # Health-related schemas. + Health: + type: object + required: + - status + - version + - commit + - build_date + properties: + status: + type: string + description: "Health status" + example: "ok" + version: + type: string + description: "Service version" + example: "1.0.0" + commit: + type: string + description: "Service commit" + example: "c1b2d3f4" + build_date: + type: string + description: "Service build date" + example: "2022-01-01T00:00:00Z" + format: date-time + responses: + Error: + description: Structured error response. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + diff --git a/testutil/tgacc/oas_cfg_gen.go b/testutil/tgacc/oas_cfg_gen.go new file mode 100644 index 000000000..81065ae3c --- /dev/null +++ b/testutil/tgacc/oas_cfg_gen.go @@ -0,0 +1,143 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "net/http" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/ogenregex" + "github.com/ogen-go/ogen/otelogen" +) + +var regexMap = map[string]ogenregex.Regexp{ + "[[:xdigit:]]{16}": ogenregex.MustCompile("[[:xdigit:]]{16}"), + "[[:xdigit:]]{32}": ogenregex.MustCompile("[[:xdigit:]]{32}"), + "^[0-9]{3,6}$": ogenregex.MustCompile("^[0-9]{3,6}$"), + "^[0-9]{7,15}$": ogenregex.MustCompile("^[0-9]{7,15}$"), +} +var ( + // Allocate option closure once. + clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) +) + +type ( + optionFunc[C any] func(*C) + otelOptionFunc func(*otelConfig) +) + +type otelConfig struct { + TracerProvider trace.TracerProvider + Tracer trace.Tracer + MeterProvider metric.MeterProvider + Meter metric.Meter +} + +func (cfg *otelConfig) initOTEL() { + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + if cfg.MeterProvider == nil { + cfg.MeterProvider = otel.GetMeterProvider() + } + cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, + trace.WithInstrumentationVersion(otelogen.SemVersion()), + ) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name, + metric.WithInstrumentationVersion(otelogen.SemVersion()), + ) +} + +type clientConfig struct { + otelConfig + Client ht.Client +} + +// ClientOption is client config option. +type ClientOption interface { + applyClient(*clientConfig) +} + +var _ ClientOption = (optionFunc[clientConfig])(nil) + +func (o optionFunc[C]) applyClient(c *C) { + o(c) +} + +var _ ClientOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyClient(c *clientConfig) { + o(&c.otelConfig) +} + +func newClientConfig(opts ...ClientOption) clientConfig { + cfg := clientConfig{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt.applyClient(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseClient struct { + cfg clientConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (cfg clientConfig) baseClient() (c baseClient, err error) { + c = baseClient{cfg: cfg} + if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil { + return c, err + } + return c, nil +} + +// Option is config option. +type Option interface { + ClientOption +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +// +// If none is specified, the global provider is used. +func WithTracerProvider(provider trace.TracerProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.TracerProvider = provider + } + }) +} + +// WithMeterProvider specifies a meter provider to use for creating a meter. +// +// If none is specified, the otel.GetMeterProvider() is used. +func WithMeterProvider(provider metric.MeterProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.MeterProvider = provider + } + }) +} + +// WithClient specifies http client to use. +func WithClient(client ht.Client) ClientOption { + return optionFunc[clientConfig](func(cfg *clientConfig) { + if client != nil { + cfg.Client = client + } + }) +} diff --git a/testutil/tgacc/oas_client_gen.go b/testutil/tgacc/oas_client_gen.go new file mode 100644 index 000000000..927813b3e --- /dev/null +++ b/testutil/tgacc/oas_client_gen.go @@ -0,0 +1,478 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "go.opentelemetry.io/otel/trace" + + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" + "github.com/ogen-go/ogen/uri" +) + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // AcquireTelegramAccount invokes acquireTelegramAccount operation. + // + // Acquire telegram account. + // + // POST /api/telegram/account/acquire + AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) + // GetHealth invokes getHealth operation. + // + // Get health. + // + // GET /api/health + GetHealth(ctx context.Context) (*Health, error) + // HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. + // + // Heartbeat telegram account. + // + // GET /api/telegram/account/heartbeat/{token} + HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error + // ReceiveTelegramCode invokes receiveTelegramCode operation. + // + // Receive telegram code. + // + // GET /api/telegram/code/receive/{token} + ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) +} + +// Client implements OAS client. +type Client struct { + serverURL *url.URL + sec SecuritySource + baseClient +} + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// NewClient initializes new Client defined by OAS. +func NewClient(serverURL string, sec SecuritySource, opts ...ClientOption) (*Client, error) { + u, err := url.Parse(serverURL) + if err != nil { + return nil, err + } + trimTrailingSlashes(u) + + c, err := newClientConfig(opts...).baseClient() + if err != nil { + return nil, err + } + return &Client{ + serverURL: u, + sec: sec, + baseClient: c, + }, nil +} + +type serverURLKey struct{} + +// WithServerURL sets context key to override server URL. +func WithServerURL(ctx context.Context, u *url.URL) context.Context { + return context.WithValue(ctx, serverURLKey{}, u) +} + +func (c *Client) requestURL(ctx context.Context) *url.URL { + u, ok := ctx.Value(serverURLKey{}).(*url.URL) + if !ok { + return c.serverURL + } + return u +} + +// AcquireTelegramAccount invokes acquireTelegramAccount operation. +// +// Acquire telegram account. +// +// POST /api/telegram/account/acquire +func (c *Client) AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) { + res, err := c.sendAcquireTelegramAccount(ctx, request) + return res, err +} + +func (c *Client) sendAcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (res *AcquireTelegramAccountOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("acquireTelegramAccount"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/api/telegram/account/acquire"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, AcquireTelegramAccountOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/api/telegram/account/acquire" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeAcquireTelegramAccountRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + { + type bitset = [1]uint8 + var satisfied bitset + { + stage = "Security:TokenAuth" + switch err := c.securityTokenAuth(ctx, AcquireTelegramAccountOperation, r); { + case err == nil: // if NO error + satisfied[0] |= 1 << 0 + case errors.Is(err, ogenerrors.ErrSkipClientSecurity): + // Skip this security. + default: + return res, errors.Wrap(err, "security \"TokenAuth\"") + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied + } + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeAcquireTelegramAccountResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GetHealth invokes getHealth operation. +// +// Get health. +// +// GET /api/health +func (c *Client) GetHealth(ctx context.Context) (*Health, error) { + res, err := c.sendGetHealth(ctx) + return res, err +} + +func (c *Client) sendGetHealth(ctx context.Context) (res *Health, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getHealth"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/health"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, GetHealthOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/api/health" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGetHealthResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. +// +// Heartbeat telegram account. +// +// GET /api/telegram/account/heartbeat/{token} +func (c *Client) HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error { + _, err := c.sendHeartbeatTelegramAccount(ctx, params) + return err +} + +func (c *Client) sendHeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) (res *HeartbeatTelegramAccountOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("heartbeatTelegramAccount"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/telegram/account/heartbeat/{token}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, HeartbeatTelegramAccountOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/api/telegram/account/heartbeat/" + { + // Encode "token" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "token", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.UUIDToString(params.Token)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "forget" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "forget", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Forget.Get(); ok { + return e.EncodeValue(conv.BoolToString(val)) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeHeartbeatTelegramAccountResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// ReceiveTelegramCode invokes receiveTelegramCode operation. +// +// Receive telegram code. +// +// GET /api/telegram/code/receive/{token} +func (c *Client) ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) { + res, err := c.sendReceiveTelegramCode(ctx, params) + return res, err +} + +func (c *Client) sendReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (res *ReceiveTelegramCodeOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("receiveTelegramCode"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/telegram/code/receive/{token}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, ReceiveTelegramCodeOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/api/telegram/code/receive/" + { + // Encode "token" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "token", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.UUIDToString(params.Token)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeReceiveTelegramCodeResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/testutil/tgacc/oas_json_gen.go b/testutil/tgacc/oas_json_gen.go new file mode 100644 index 000000000..4792130b1 --- /dev/null +++ b/testutil/tgacc/oas_json_gen.go @@ -0,0 +1,850 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "math/bits" + "strconv" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/json" + "github.com/ogen-go/ogen/validate" +) + +// Encode implements json.Marshaler. +func (s *AcquireTelegramAccountOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *AcquireTelegramAccountOK) encodeFields(e *jx.Encoder) { + { + e.FieldStart("account_id") + s.AccountID.Encode(e) + } + { + e.FieldStart("token") + json.EncodeUUID(e, s.Token) + } +} + +var jsonFieldsNameOfAcquireTelegramAccountOK = [2]string{ + 0: "account_id", + 1: "token", +} + +// Decode decodes AcquireTelegramAccountOK from json. +func (s *AcquireTelegramAccountOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode AcquireTelegramAccountOK to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "account_id": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.AccountID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"account_id\"") + } + case "token": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := json.DecodeUUID(d) + s.Token = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"token\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode AcquireTelegramAccountOK") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountOK) { + name = jsonFieldsNameOfAcquireTelegramAccountOK[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *AcquireTelegramAccountOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *AcquireTelegramAccountOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *AcquireTelegramAccountReq) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *AcquireTelegramAccountReq) encodeFields(e *jx.Encoder) { + { + e.FieldStart("repo_owner") + e.Str(s.RepoOwner) + } + { + e.FieldStart("repo_name") + e.Str(s.RepoName) + } + { + e.FieldStart("job") + e.Str(s.Job) + } + { + e.FieldStart("run_id") + e.Int64(s.RunID) + } + { + e.FieldStart("run_attempt") + e.Int(s.RunAttempt) + } +} + +var jsonFieldsNameOfAcquireTelegramAccountReq = [5]string{ + 0: "repo_owner", + 1: "repo_name", + 2: "job", + 3: "run_id", + 4: "run_attempt", +} + +// Decode decodes AcquireTelegramAccountReq from json. +func (s *AcquireTelegramAccountReq) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode AcquireTelegramAccountReq to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "repo_owner": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.RepoOwner = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repo_owner\"") + } + case "repo_name": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.RepoName = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repo_name\"") + } + case "job": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Str() + s.Job = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"job\"") + } + case "run_id": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Int64() + s.RunID = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"run_id\"") + } + case "run_attempt": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Int() + s.RunAttempt = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"run_attempt\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode AcquireTelegramAccountReq") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00011111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountReq) { + name = jsonFieldsNameOfAcquireTelegramAccountReq[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *AcquireTelegramAccountReq) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *AcquireTelegramAccountReq) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Error) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Error) encodeFields(e *jx.Encoder) { + { + e.FieldStart("error_message") + e.Str(s.ErrorMessage) + } + { + if s.TraceID.Set { + e.FieldStart("trace_id") + s.TraceID.Encode(e) + } + } + { + if s.SpanID.Set { + e.FieldStart("span_id") + s.SpanID.Encode(e) + } + } +} + +var jsonFieldsNameOfError = [3]string{ + 0: "error_message", + 1: "trace_id", + 2: "span_id", +} + +// Decode decodes Error from json. +func (s *Error) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Error to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "error_message": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.ErrorMessage = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"error_message\"") + } + case "trace_id": + if err := func() error { + s.TraceID.Reset() + if err := s.TraceID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"trace_id\"") + } + case "span_id": + if err := func() error { + s.SpanID.Reset() + if err := s.SpanID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"span_id\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Error") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfError) { + name = jsonFieldsNameOfError[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Error) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Error) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Health) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Health) encodeFields(e *jx.Encoder) { + { + e.FieldStart("status") + e.Str(s.Status) + } + { + e.FieldStart("version") + e.Str(s.Version) + } + { + e.FieldStart("commit") + e.Str(s.Commit) + } + { + e.FieldStart("build_date") + json.EncodeDateTime(e, s.BuildDate) + } +} + +var jsonFieldsNameOfHealth = [4]string{ + 0: "status", + 1: "version", + 2: "commit", + 3: "build_date", +} + +// Decode decodes Health from json. +func (s *Health) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Health to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "status": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Status = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"status\"") + } + case "version": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Version = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"version\"") + } + case "commit": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Str() + s.Commit = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"commit\"") + } + case "build_date": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := json.DecodeDateTime(d) + s.BuildDate = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"build_date\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Health") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00001111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfHealth) { + name = jsonFieldsNameOfHealth[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Health) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Health) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes SpanID as json. +func (o OptSpanID) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes SpanID from json. +func (o *OptSpanID) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptSpanID to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptSpanID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptSpanID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes string as json. +func (o OptString) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes string from json. +func (o *OptString) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptString to nil") + } + o.Set = true + v, err := d.Str() + if err != nil { + return err + } + o.Value = string(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptString) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptString) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TraceID as json. +func (o OptTraceID) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TraceID from json. +func (o *OptTraceID) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTraceID to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTraceID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTraceID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *ReceiveTelegramCodeOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ReceiveTelegramCodeOK) encodeFields(e *jx.Encoder) { + { + if s.Code.Set { + e.FieldStart("code") + s.Code.Encode(e) + } + } +} + +var jsonFieldsNameOfReceiveTelegramCodeOK = [1]string{ + 0: "code", +} + +// Decode decodes ReceiveTelegramCodeOK from json. +func (s *ReceiveTelegramCodeOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ReceiveTelegramCodeOK to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "code": + if err := func() error { + s.Code.Reset() + if err := s.Code.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"code\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ReceiveTelegramCodeOK") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ReceiveTelegramCodeOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ReceiveTelegramCodeOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes SpanID as json. +func (s SpanID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes SpanID from json. +func (s *SpanID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode SpanID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = SpanID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s SpanID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *SpanID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TelegramAccountID as json. +func (s TelegramAccountID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes TelegramAccountID from json. +func (s *TelegramAccountID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TelegramAccountID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = TelegramAccountID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TelegramAccountID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TelegramAccountID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TraceID as json. +func (s TraceID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes TraceID from json. +func (s *TraceID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TraceID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = TraceID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TraceID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TraceID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/testutil/tgacc/oas_operations_gen.go b/testutil/tgacc/oas_operations_gen.go new file mode 100644 index 000000000..25b935d34 --- /dev/null +++ b/testutil/tgacc/oas_operations_gen.go @@ -0,0 +1,13 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +// OperationName is the ogen operation name +type OperationName = string + +const ( + AcquireTelegramAccountOperation OperationName = "AcquireTelegramAccount" + GetHealthOperation OperationName = "GetHealth" + HeartbeatTelegramAccountOperation OperationName = "HeartbeatTelegramAccount" + ReceiveTelegramCodeOperation OperationName = "ReceiveTelegramCode" +) diff --git a/testutil/tgacc/oas_parameters_gen.go b/testutil/tgacc/oas_parameters_gen.go new file mode 100644 index 000000000..4ebb7014c --- /dev/null +++ b/testutil/tgacc/oas_parameters_gen.go @@ -0,0 +1,18 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "github.com/google/uuid" +) + +// HeartbeatTelegramAccountParams is parameters of heartbeatTelegramAccount operation. +type HeartbeatTelegramAccountParams struct { + Token uuid.UUID + Forget OptBool +} + +// ReceiveTelegramCodeParams is parameters of receiveTelegramCode operation. +type ReceiveTelegramCodeParams struct { + Token uuid.UUID +} diff --git a/testutil/tgacc/oas_request_encoders_gen.go b/testutil/tgacc/oas_request_encoders_gen.go new file mode 100644 index 000000000..c55309923 --- /dev/null +++ b/testutil/tgacc/oas_request_encoders_gen.go @@ -0,0 +1,26 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "bytes" + "net/http" + + "github.com/go-faster/jx" + + ht "github.com/ogen-go/ogen/http" +) + +func encodeAcquireTelegramAccountRequest( + req *AcquireTelegramAccountReq, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} diff --git a/testutil/tgacc/oas_response_decoders_gen.go b/testutil/tgacc/oas_response_decoders_gen.go new file mode 100644 index 000000000..1d4d1dc54 --- /dev/null +++ b/testutil/tgacc/oas_response_decoders_gen.go @@ -0,0 +1,369 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func decodeAcquireTelegramAccountResponse(resp *http.Response) (res *AcquireTelegramAccountOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response AcquireTelegramAccountOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGetHealthResponse(resp *http.Response) (res *Health, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Health + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeHeartbeatTelegramAccountResponse(resp *http.Response) (res *HeartbeatTelegramAccountOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + return &HeartbeatTelegramAccountOK{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeReceiveTelegramCodeResponse(resp *http.Response) (res *ReceiveTelegramCodeOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response ReceiveTelegramCodeOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} diff --git a/testutil/tgacc/oas_schemas_gen.go b/testutil/tgacc/oas_schemas_gen.go new file mode 100644 index 000000000..e07bfe699 --- /dev/null +++ b/testutil/tgacc/oas_schemas_gen.go @@ -0,0 +1,440 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "fmt" + "time" + + "github.com/google/uuid" +) + +func (s *ErrorStatusCode) Error() string { + return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) +} + +type AcquireTelegramAccountOK struct { + AccountID TelegramAccountID `json:"account_id"` + // Access token. + Token uuid.UUID `json:"token"` +} + +// GetAccountID returns the value of AccountID. +func (s *AcquireTelegramAccountOK) GetAccountID() TelegramAccountID { + return s.AccountID +} + +// GetToken returns the value of Token. +func (s *AcquireTelegramAccountOK) GetToken() uuid.UUID { + return s.Token +} + +// SetAccountID sets the value of AccountID. +func (s *AcquireTelegramAccountOK) SetAccountID(val TelegramAccountID) { + s.AccountID = val +} + +// SetToken sets the value of Token. +func (s *AcquireTelegramAccountOK) SetToken(val uuid.UUID) { + s.Token = val +} + +type AcquireTelegramAccountReq struct { + // Repository owner. + RepoOwner string `json:"repo_owner"` + // Repository name. + RepoName string `json:"repo_name"` + // Job ID. + Job string `json:"job"` + RunID int64 `json:"run_id"` + RunAttempt int `json:"run_attempt"` +} + +// GetRepoOwner returns the value of RepoOwner. +func (s *AcquireTelegramAccountReq) GetRepoOwner() string { + return s.RepoOwner +} + +// GetRepoName returns the value of RepoName. +func (s *AcquireTelegramAccountReq) GetRepoName() string { + return s.RepoName +} + +// GetJob returns the value of Job. +func (s *AcquireTelegramAccountReq) GetJob() string { + return s.Job +} + +// GetRunID returns the value of RunID. +func (s *AcquireTelegramAccountReq) GetRunID() int64 { + return s.RunID +} + +// GetRunAttempt returns the value of RunAttempt. +func (s *AcquireTelegramAccountReq) GetRunAttempt() int { + return s.RunAttempt +} + +// SetRepoOwner sets the value of RepoOwner. +func (s *AcquireTelegramAccountReq) SetRepoOwner(val string) { + s.RepoOwner = val +} + +// SetRepoName sets the value of RepoName. +func (s *AcquireTelegramAccountReq) SetRepoName(val string) { + s.RepoName = val +} + +// SetJob sets the value of Job. +func (s *AcquireTelegramAccountReq) SetJob(val string) { + s.Job = val +} + +// SetRunID sets the value of RunID. +func (s *AcquireTelegramAccountReq) SetRunID(val int64) { + s.RunID = val +} + +// SetRunAttempt sets the value of RunAttempt. +func (s *AcquireTelegramAccountReq) SetRunAttempt(val int) { + s.RunAttempt = val +} + +// Error occurred while processing request. +// Ref: #/components/schemas/Error +type Error struct { + // Human-readable error message. + ErrorMessage string `json:"error_message"` + TraceID OptTraceID `json:"trace_id"` + SpanID OptSpanID `json:"span_id"` +} + +// GetErrorMessage returns the value of ErrorMessage. +func (s *Error) GetErrorMessage() string { + return s.ErrorMessage +} + +// GetTraceID returns the value of TraceID. +func (s *Error) GetTraceID() OptTraceID { + return s.TraceID +} + +// GetSpanID returns the value of SpanID. +func (s *Error) GetSpanID() OptSpanID { + return s.SpanID +} + +// SetErrorMessage sets the value of ErrorMessage. +func (s *Error) SetErrorMessage(val string) { + s.ErrorMessage = val +} + +// SetTraceID sets the value of TraceID. +func (s *Error) SetTraceID(val OptTraceID) { + s.TraceID = val +} + +// SetSpanID sets the value of SpanID. +func (s *Error) SetSpanID(val OptSpanID) { + s.SpanID = val +} + +// ErrorStatusCode wraps Error with StatusCode. +type ErrorStatusCode struct { + StatusCode int + Response Error +} + +// GetStatusCode returns the value of StatusCode. +func (s *ErrorStatusCode) GetStatusCode() int { + return s.StatusCode +} + +// GetResponse returns the value of Response. +func (s *ErrorStatusCode) GetResponse() Error { + return s.Response +} + +// SetStatusCode sets the value of StatusCode. +func (s *ErrorStatusCode) SetStatusCode(val int) { + s.StatusCode = val +} + +// SetResponse sets the value of Response. +func (s *ErrorStatusCode) SetResponse(val Error) { + s.Response = val +} + +// Ref: #/components/schemas/Health +type Health struct { + // Health status. + Status string `json:"status"` + // Service version. + Version string `json:"version"` + // Service commit. + Commit string `json:"commit"` + // Service build date. + BuildDate time.Time `json:"build_date"` +} + +// GetStatus returns the value of Status. +func (s *Health) GetStatus() string { + return s.Status +} + +// GetVersion returns the value of Version. +func (s *Health) GetVersion() string { + return s.Version +} + +// GetCommit returns the value of Commit. +func (s *Health) GetCommit() string { + return s.Commit +} + +// GetBuildDate returns the value of BuildDate. +func (s *Health) GetBuildDate() time.Time { + return s.BuildDate +} + +// SetStatus sets the value of Status. +func (s *Health) SetStatus(val string) { + s.Status = val +} + +// SetVersion sets the value of Version. +func (s *Health) SetVersion(val string) { + s.Version = val +} + +// SetCommit sets the value of Commit. +func (s *Health) SetCommit(val string) { + s.Commit = val +} + +// SetBuildDate sets the value of BuildDate. +func (s *Health) SetBuildDate(val time.Time) { + s.BuildDate = val +} + +// HeartbeatTelegramAccountOK is response for HeartbeatTelegramAccount operation. +type HeartbeatTelegramAccountOK struct{} + +// NewOptBool returns new OptBool with value set to v. +func NewOptBool(v bool) OptBool { + return OptBool{ + Value: v, + Set: true, + } +} + +// OptBool is optional bool. +type OptBool struct { + Value bool + Set bool +} + +// IsSet returns true if OptBool was set. +func (o OptBool) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBool) Reset() { + var v bool + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBool) SetTo(v bool) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBool) Get() (v bool, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBool) Or(d bool) bool { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptSpanID returns new OptSpanID with value set to v. +func NewOptSpanID(v SpanID) OptSpanID { + return OptSpanID{ + Value: v, + Set: true, + } +} + +// OptSpanID is optional SpanID. +type OptSpanID struct { + Value SpanID + Set bool +} + +// IsSet returns true if OptSpanID was set. +func (o OptSpanID) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptSpanID) Reset() { + var v SpanID + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptSpanID) SetTo(v SpanID) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptSpanID) Get() (v SpanID, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptSpanID) Or(d SpanID) SpanID { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptString returns new OptString with value set to v. +func NewOptString(v string) OptString { + return OptString{ + Value: v, + Set: true, + } +} + +// OptString is optional string. +type OptString struct { + Value string + Set bool +} + +// IsSet returns true if OptString was set. +func (o OptString) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptString) Reset() { + var v string + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptString) SetTo(v string) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptString) Get() (v string, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptString) Or(d string) string { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTraceID returns new OptTraceID with value set to v. +func NewOptTraceID(v TraceID) OptTraceID { + return OptTraceID{ + Value: v, + Set: true, + } +} + +// OptTraceID is optional TraceID. +type OptTraceID struct { + Value TraceID + Set bool +} + +// IsSet returns true if OptTraceID was set. +func (o OptTraceID) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTraceID) Reset() { + var v TraceID + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTraceID) SetTo(v TraceID) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTraceID) Get() (v TraceID, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTraceID) Or(d TraceID) TraceID { + if v, ok := o.Get(); ok { + return v + } + return d +} + +type ReceiveTelegramCodeOK struct { + // Code. + Code OptString `json:"code"` +} + +// GetCode returns the value of Code. +func (s *ReceiveTelegramCodeOK) GetCode() OptString { + return s.Code +} + +// SetCode sets the value of Code. +func (s *ReceiveTelegramCodeOK) SetCode(val OptString) { + s.Code = val +} + +type SpanID string + +type TelegramAccountID string + +type TokenAuth struct { + APIKey string +} + +// GetAPIKey returns the value of APIKey. +func (s *TokenAuth) GetAPIKey() string { + return s.APIKey +} + +// SetAPIKey sets the value of APIKey. +func (s *TokenAuth) SetAPIKey(val string) { + s.APIKey = val +} + +type TraceID string diff --git a/testutil/tgacc/oas_security_gen.go b/testutil/tgacc/oas_security_gen.go new file mode 100644 index 000000000..489ab849f --- /dev/null +++ b/testutil/tgacc/oas_security_gen.go @@ -0,0 +1,25 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "context" + "net/http" + + "github.com/go-faster/errors" +) + +// SecuritySource is provider of security values (tokens, passwords, etc.). +type SecuritySource interface { + // TokenAuth provides tokenAuth security value. + TokenAuth(ctx context.Context, operationName OperationName) (TokenAuth, error) +} + +func (s *Client) securityTokenAuth(ctx context.Context, operationName OperationName, req *http.Request) error { + t, err := s.sec.TokenAuth(ctx, operationName) + if err != nil { + return errors.Wrap(err, "security source \"TokenAuth\"") + } + req.Header.Set("Token", t.APIKey) + return nil +} diff --git a/testutil/tgacc/oas_validators_gen.go b/testutil/tgacc/oas_validators_gen.go new file mode 100644 index 000000000..a7add8830 --- /dev/null +++ b/testutil/tgacc/oas_validators_gen.go @@ -0,0 +1,189 @@ +// Code generated by ogen, DO NOT EDIT. + +package tgacc + +import ( + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/validate" +) + +func (s *AcquireTelegramAccountOK) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.AccountID.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "account_id", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *Error) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.TraceID.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "trace_id", + Error: err, + }) + } + if err := func() error { + if value, ok := s.SpanID.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "span_id", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *ErrorStatusCode) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.Response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "Response", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *ReceiveTelegramCodeOK) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.Code.Get(); ok { + if err := func() error { + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["^[0-9]{3,6}$"], + }).Validate(string(value)); err != nil { + return errors.Wrap(err, "string") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "code", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s SpanID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["[[:xdigit:]]{16}"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} + +func (s TelegramAccountID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["^[0-9]{7,15}$"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} + +func (s TraceID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["[[:xdigit:]]{32}"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} diff --git a/testutil/tgacc_test.go b/testutil/tgacc_test.go new file mode 100644 index 000000000..c8b4f114c --- /dev/null +++ b/testutil/tgacc_test.go @@ -0,0 +1,23 @@ +package testutil + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestExternalE2E(t *testing.T) { + SkipExternal(t) + + manager, err := NewTestAccountManager() + require.NoError(t, err) + + ctx := context.Background() + client, err := manager.Acquire(ctx) + require.NoError(t, err) + + t.Cleanup(func() { + require.NoError(t, client.Close()) + }) +} diff --git a/testutil/tools.go b/testutil/tools.go new file mode 100644 index 000000000..bb0c4c6e9 --- /dev/null +++ b/testutil/tools.go @@ -0,0 +1,13 @@ +//go:build testutil + +package bot + +import ( + _ "github.com/ogen-go/ogen" + _ "github.com/ogen-go/ogen/conv" + _ "github.com/ogen-go/ogen/gen" + _ "github.com/ogen-go/ogen/gen/genfs" + _ "github.com/ogen-go/ogen/middleware" + _ "github.com/ogen-go/ogen/ogenerrors" + _ "github.com/ogen-go/ogen/otelogen" +) From 1762675b23e0ff5fe4bfc3679a7da27e2e1eaf23 Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:21:05 +0300 Subject: [PATCH 02/11] ci: configure e2e --- .github/workflows/e2e.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 3893aecd1..2b56ecaea 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -45,3 +45,7 @@ jobs: GOTD_TEST_EXTERNAL: 1 GOTD_MTPROXY_ADDR: "127.0.0.1:3128" GOTD_E2E_DIALOGS_BROKEN: 1 # TODO(ernado): enable when fixed + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_JOB_ID: ${{ github.job }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }} From ce3c6a6f7488632f151d9f3251784052a87927de Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:44:01 +0300 Subject: [PATCH 03/11] test: use real phones for e2e tests Ref: https://github.com/tdlib/td/issues/3083 --- .github/workflows/e2e.yml | 2 +- telegram/internal/e2etest/auth.go | 14 +++++++++- telegram/internal/e2etest/auth_test.go | 3 ++ telegram/internal/e2etest/suite.go | 38 ++++++++++++++++++++++---- testutil/tgacc.go | 6 ++-- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2b56ecaea..eb88844e1 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -44,7 +44,7 @@ jobs: env: GOTD_TEST_EXTERNAL: 1 GOTD_MTPROXY_ADDR: "127.0.0.1:3128" - GOTD_E2E_DIALOGS_BROKEN: 1 # TODO(ernado): enable when fixed + TEST_ACCOUNTS_BROKEN: 1 # use external test accounts GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_JOB_ID: ${{ github.job }} GITHUB_RUN_ID: ${{ github.run_id }} diff --git a/telegram/internal/e2etest/auth.go b/telegram/internal/e2etest/auth.go index 64279882c..e2628892a 100644 --- a/telegram/internal/e2etest/auth.go +++ b/telegram/internal/e2etest/auth.go @@ -2,6 +2,7 @@ package e2etest import ( "context" + "time" "github.com/cenkalti/backoff/v4" "github.com/go-faster/errors" @@ -10,6 +11,14 @@ import ( ) func (s *Suite) createFlow(ctx context.Context) (auth.Flow, error) { + if s.manager != nil { + account, err := s.manager.Acquire(ctx) + if err != nil { + return auth.Flow{}, errors.Wrap(err, "acquire account") + } + return auth.NewFlow(account.UserAuthenticator, auth.SendCodeOptions{}), nil + } + var ua auth.UserAuthenticator for { ua = auth.Test(s.rand, s.dc) @@ -51,7 +60,10 @@ func (s *Suite) Authenticate(ctx context.Context, client auth.FlowClient) error // RetryAuthenticate authenticates client on test server. func (s *Suite) RetryAuthenticate(ctx context.Context, client auth.FlowClient) error { - bck := backoff.WithContext(backoff.NewExponentialBackOff(), ctx) + bc := backoff.NewExponentialBackOff() + bc.MaxElapsedTime = time.Minute + bc.MaxInterval = time.Second * 3 + bck := backoff.WithContext(bc, ctx) return backoff.Retry(func() error { return s.Authenticate(ctx, client) }, bck) diff --git a/telegram/internal/e2etest/auth_test.go b/telegram/internal/e2etest/auth_test.go index 5e3b68525..6c3a625b9 100644 --- a/telegram/internal/e2etest/auth_test.go +++ b/telegram/internal/e2etest/auth_test.go @@ -55,6 +55,9 @@ func TestSuite_Authenticate(t *testing.T) { s := NewSuite(t, TestOptions{ Logger: logger, }) + if s.manager != nil { + t.Skip("Not testing external manager") + } flow := &mockFlow{} require.NoError(t, s.Authenticate(ctx, flow)) diff --git a/telegram/internal/e2etest/suite.go b/telegram/internal/e2etest/suite.go index 0a222ccf1..9167df3d1 100644 --- a/telegram/internal/e2etest/suite.go +++ b/telegram/internal/e2etest/suite.go @@ -2,13 +2,17 @@ package e2etest import ( "io" + "os" + "strconv" "sync" + "testing" "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/dcs" + "github.com/gotd/td/testutil" ) // Suite is struct which contains external E2E test parameters. @@ -18,6 +22,8 @@ type Suite struct { appHash string dc int logger *zap.Logger + manager *testutil.TestAccountManager + closers []func() error rand io.Reader // already used phone numbers @@ -25,18 +31,40 @@ type Suite struct { usedMux sync.Mutex } +// Close closes all resources. +func (s *Suite) Close() error { + var err error + for _, closer := range s.closers { + if e := closer(); e != nil { + err = e + } + } + return err +} + // NewSuite creates new Suite. -func NewSuite(tb require.TestingT, config TestOptions) *Suite { +func NewSuite(t *testing.T, config TestOptions) *Suite { config.setDefaults() - return &Suite{ - TB: tb, + manager, err := testutil.NewTestAccountManager() + require.NoError(t, err) + s := &Suite{ + TB: t, appID: config.AppID, appHash: config.AppHash, dc: config.DC, logger: config.Logger, - rand: config.Random, - used: map[string]struct{}{}, + manager: manager, } + if managerEnabled, _ := strconv.ParseBool(os.Getenv("TEST_ACCOUNTS_BROKEN")); managerEnabled { + t.Log("External test accounts are used as per TEST_ACCOUNTS_BROKEN") + } else { + t.Log("Normal test accounts are used") + s.manager = nil // disable manager + } + t.Cleanup(func() { + require.NoError(t, s.Close()) + }) + return s } // Client creates new *telegram.Client using this suite. diff --git a/testutil/tgacc.go b/testutil/tgacc.go index 1af9205a0..93fba58d5 100644 --- a/testutil/tgacc.go +++ b/testutil/tgacc.go @@ -45,7 +45,7 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) return &TestAccount{ Phone: phone, - AuthFlow: &codeAuth{ + UserAuthenticator: &codeAuth{ phone: phone, client: t.client, }, @@ -64,8 +64,8 @@ func (s ghSecuritySource) TokenAuth(ctx context.Context, operationName tgacc.Ope } type TestAccount struct { - Phone string - AuthFlow auth.UserAuthenticator + Phone string + UserAuthenticator auth.UserAuthenticator token uuid.UUID client *tgacc.Client From 343fbd48f1b604794cfb7caa0b9be399b38d6a43 Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:47:50 +0300 Subject: [PATCH 04/11] test: move tgacc to separate package --- telegram/internal/e2etest/suite.go | 6 +- testutil/generate.go | 3 - testutil/tgacc/oas_cfg_gen.go | 143 ---- testutil/tgacc/oas_client_gen.go | 478 ----------- testutil/tgacc/oas_json_gen.go | 850 -------------------- testutil/tgacc/oas_operations_gen.go | 13 - testutil/tgacc/oas_parameters_gen.go | 18 - testutil/tgacc/oas_request_encoders_gen.go | 26 - testutil/tgacc/oas_response_decoders_gen.go | 369 --------- testutil/tgacc/oas_schemas_gen.go | 440 ---------- testutil/tgacc/oas_security_gen.go | 25 - testutil/tgacc/oas_validators_gen.go | 189 ----- {testutil => tgacc}/.ogen.yml | 0 tgacc/generate.go | 3 + {testutil => tgacc}/tgacc.go | 24 +- {testutil => tgacc}/tgacc.openapi.yaml | 0 {testutil => tgacc}/tgacc_test.go | 6 +- 17 files changed, 22 insertions(+), 2571 deletions(-) delete mode 100644 testutil/generate.go delete mode 100644 testutil/tgacc/oas_cfg_gen.go delete mode 100644 testutil/tgacc/oas_client_gen.go delete mode 100644 testutil/tgacc/oas_json_gen.go delete mode 100644 testutil/tgacc/oas_operations_gen.go delete mode 100644 testutil/tgacc/oas_parameters_gen.go delete mode 100644 testutil/tgacc/oas_request_encoders_gen.go delete mode 100644 testutil/tgacc/oas_response_decoders_gen.go delete mode 100644 testutil/tgacc/oas_schemas_gen.go delete mode 100644 testutil/tgacc/oas_security_gen.go delete mode 100644 testutil/tgacc/oas_validators_gen.go rename {testutil => tgacc}/.ogen.yml (100%) create mode 100644 tgacc/generate.go rename {testutil => tgacc}/tgacc.go (82%) rename {testutil => tgacc}/tgacc.openapi.yaml (100%) rename {testutil => tgacc}/tgacc_test.go (82%) diff --git a/telegram/internal/e2etest/suite.go b/telegram/internal/e2etest/suite.go index 9167df3d1..1143ac9d4 100644 --- a/telegram/internal/e2etest/suite.go +++ b/telegram/internal/e2etest/suite.go @@ -12,7 +12,7 @@ import ( "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/testutil" + "github.com/gotd/td/tgacc" ) // Suite is struct which contains external E2E test parameters. @@ -22,7 +22,7 @@ type Suite struct { appHash string dc int logger *zap.Logger - manager *testutil.TestAccountManager + manager *tgacc.TestAccountManager closers []func() error rand io.Reader @@ -45,7 +45,7 @@ func (s *Suite) Close() error { // NewSuite creates new Suite. func NewSuite(t *testing.T, config TestOptions) *Suite { config.setDefaults() - manager, err := testutil.NewTestAccountManager() + manager, err := tgacc.NewTestAccountManager() require.NoError(t, err) s := &Suite{ TB: t, diff --git a/testutil/generate.go b/testutil/generate.go deleted file mode 100644 index 31b9ed134..000000000 --- a/testutil/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -package testutil - -//go:generate go run -mod=mod github.com/ogen-go/ogen/cmd/ogen --target tgacc --package tgacc --clean tgacc.openapi.yaml diff --git a/testutil/tgacc/oas_cfg_gen.go b/testutil/tgacc/oas_cfg_gen.go deleted file mode 100644 index 81065ae3c..000000000 --- a/testutil/tgacc/oas_cfg_gen.go +++ /dev/null @@ -1,143 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "net/http" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/trace" - - ht "github.com/ogen-go/ogen/http" - "github.com/ogen-go/ogen/ogenregex" - "github.com/ogen-go/ogen/otelogen" -) - -var regexMap = map[string]ogenregex.Regexp{ - "[[:xdigit:]]{16}": ogenregex.MustCompile("[[:xdigit:]]{16}"), - "[[:xdigit:]]{32}": ogenregex.MustCompile("[[:xdigit:]]{32}"), - "^[0-9]{3,6}$": ogenregex.MustCompile("^[0-9]{3,6}$"), - "^[0-9]{7,15}$": ogenregex.MustCompile("^[0-9]{7,15}$"), -} -var ( - // Allocate option closure once. - clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) -) - -type ( - optionFunc[C any] func(*C) - otelOptionFunc func(*otelConfig) -) - -type otelConfig struct { - TracerProvider trace.TracerProvider - Tracer trace.Tracer - MeterProvider metric.MeterProvider - Meter metric.Meter -} - -func (cfg *otelConfig) initOTEL() { - if cfg.TracerProvider == nil { - cfg.TracerProvider = otel.GetTracerProvider() - } - if cfg.MeterProvider == nil { - cfg.MeterProvider = otel.GetMeterProvider() - } - cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, - trace.WithInstrumentationVersion(otelogen.SemVersion()), - ) - cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name, - metric.WithInstrumentationVersion(otelogen.SemVersion()), - ) -} - -type clientConfig struct { - otelConfig - Client ht.Client -} - -// ClientOption is client config option. -type ClientOption interface { - applyClient(*clientConfig) -} - -var _ ClientOption = (optionFunc[clientConfig])(nil) - -func (o optionFunc[C]) applyClient(c *C) { - o(c) -} - -var _ ClientOption = (otelOptionFunc)(nil) - -func (o otelOptionFunc) applyClient(c *clientConfig) { - o(&c.otelConfig) -} - -func newClientConfig(opts ...ClientOption) clientConfig { - cfg := clientConfig{ - Client: http.DefaultClient, - } - for _, opt := range opts { - opt.applyClient(&cfg) - } - cfg.initOTEL() - return cfg -} - -type baseClient struct { - cfg clientConfig - requests metric.Int64Counter - errors metric.Int64Counter - duration metric.Float64Histogram -} - -func (cfg clientConfig) baseClient() (c baseClient, err error) { - c = baseClient{cfg: cfg} - if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil { - return c, err - } - if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil { - return c, err - } - if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil { - return c, err - } - return c, nil -} - -// Option is config option. -type Option interface { - ClientOption -} - -// WithTracerProvider specifies a tracer provider to use for creating a tracer. -// -// If none is specified, the global provider is used. -func WithTracerProvider(provider trace.TracerProvider) Option { - return otelOptionFunc(func(cfg *otelConfig) { - if provider != nil { - cfg.TracerProvider = provider - } - }) -} - -// WithMeterProvider specifies a meter provider to use for creating a meter. -// -// If none is specified, the otel.GetMeterProvider() is used. -func WithMeterProvider(provider metric.MeterProvider) Option { - return otelOptionFunc(func(cfg *otelConfig) { - if provider != nil { - cfg.MeterProvider = provider - } - }) -} - -// WithClient specifies http client to use. -func WithClient(client ht.Client) ClientOption { - return optionFunc[clientConfig](func(cfg *clientConfig) { - if client != nil { - cfg.Client = client - } - }) -} diff --git a/testutil/tgacc/oas_client_gen.go b/testutil/tgacc/oas_client_gen.go deleted file mode 100644 index 927813b3e..000000000 --- a/testutil/tgacc/oas_client_gen.go +++ /dev/null @@ -1,478 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "context" - "net/url" - "strings" - "time" - - "github.com/go-faster/errors" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" - "go.opentelemetry.io/otel/trace" - - "github.com/ogen-go/ogen/conv" - ht "github.com/ogen-go/ogen/http" - "github.com/ogen-go/ogen/ogenerrors" - "github.com/ogen-go/ogen/otelogen" - "github.com/ogen-go/ogen/uri" -) - -// Invoker invokes operations described by OpenAPI v3 specification. -type Invoker interface { - // AcquireTelegramAccount invokes acquireTelegramAccount operation. - // - // Acquire telegram account. - // - // POST /api/telegram/account/acquire - AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) - // GetHealth invokes getHealth operation. - // - // Get health. - // - // GET /api/health - GetHealth(ctx context.Context) (*Health, error) - // HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. - // - // Heartbeat telegram account. - // - // GET /api/telegram/account/heartbeat/{token} - HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error - // ReceiveTelegramCode invokes receiveTelegramCode operation. - // - // Receive telegram code. - // - // GET /api/telegram/code/receive/{token} - ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) -} - -// Client implements OAS client. -type Client struct { - serverURL *url.URL - sec SecuritySource - baseClient -} - -func trimTrailingSlashes(u *url.URL) { - u.Path = strings.TrimRight(u.Path, "/") - u.RawPath = strings.TrimRight(u.RawPath, "/") -} - -// NewClient initializes new Client defined by OAS. -func NewClient(serverURL string, sec SecuritySource, opts ...ClientOption) (*Client, error) { - u, err := url.Parse(serverURL) - if err != nil { - return nil, err - } - trimTrailingSlashes(u) - - c, err := newClientConfig(opts...).baseClient() - if err != nil { - return nil, err - } - return &Client{ - serverURL: u, - sec: sec, - baseClient: c, - }, nil -} - -type serverURLKey struct{} - -// WithServerURL sets context key to override server URL. -func WithServerURL(ctx context.Context, u *url.URL) context.Context { - return context.WithValue(ctx, serverURLKey{}, u) -} - -func (c *Client) requestURL(ctx context.Context) *url.URL { - u, ok := ctx.Value(serverURLKey{}).(*url.URL) - if !ok { - return c.serverURL - } - return u -} - -// AcquireTelegramAccount invokes acquireTelegramAccount operation. -// -// Acquire telegram account. -// -// POST /api/telegram/account/acquire -func (c *Client) AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) { - res, err := c.sendAcquireTelegramAccount(ctx, request) - return res, err -} - -func (c *Client) sendAcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (res *AcquireTelegramAccountOK, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("acquireTelegramAccount"), - semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/api/telegram/account/acquire"), - } - - // Run stopwatch. - startTime := time.Now() - defer func() { - // Use floating point division here for higher precision (instead of Millisecond method). - elapsedDuration := time.Since(startTime) - c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) - }() - - // Increment request counter. - c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - - // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, AcquireTelegramAccountOperation, - trace.WithAttributes(otelAttrs...), - clientSpanKind, - ) - // Track stage for error reporting. - var stage string - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, stage) - c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - } - span.End() - }() - - stage = "BuildURL" - u := uri.Clone(c.requestURL(ctx)) - var pathParts [1]string - pathParts[0] = "/api/telegram/account/acquire" - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "POST", u) - if err != nil { - return res, errors.Wrap(err, "create request") - } - if err := encodeAcquireTelegramAccountRequest(request, r); err != nil { - return res, errors.Wrap(err, "encode request") - } - - { - type bitset = [1]uint8 - var satisfied bitset - { - stage = "Security:TokenAuth" - switch err := c.securityTokenAuth(ctx, AcquireTelegramAccountOperation, r); { - case err == nil: // if NO error - satisfied[0] |= 1 << 0 - case errors.Is(err, ogenerrors.ErrSkipClientSecurity): - // Skip this security. - default: - return res, errors.Wrap(err, "security \"TokenAuth\"") - } - } - - if ok := func() bool { - nextRequirement: - for _, requirement := range []bitset{ - {0b00000001}, - } { - for i, mask := range requirement { - if satisfied[i]&mask != mask { - continue nextRequirement - } - } - return true - } - return false - }(); !ok { - return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied - } - } - - stage = "SendRequest" - resp, err := c.cfg.Client.Do(r) - if err != nil { - return res, errors.Wrap(err, "do request") - } - defer resp.Body.Close() - - stage = "DecodeResponse" - result, err := decodeAcquireTelegramAccountResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} - -// GetHealth invokes getHealth operation. -// -// Get health. -// -// GET /api/health -func (c *Client) GetHealth(ctx context.Context) (*Health, error) { - res, err := c.sendGetHealth(ctx) - return res, err -} - -func (c *Client) sendGetHealth(ctx context.Context) (res *Health, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("getHealth"), - semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/api/health"), - } - - // Run stopwatch. - startTime := time.Now() - defer func() { - // Use floating point division here for higher precision (instead of Millisecond method). - elapsedDuration := time.Since(startTime) - c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) - }() - - // Increment request counter. - c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - - // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, GetHealthOperation, - trace.WithAttributes(otelAttrs...), - clientSpanKind, - ) - // Track stage for error reporting. - var stage string - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, stage) - c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - } - span.End() - }() - - stage = "BuildURL" - u := uri.Clone(c.requestURL(ctx)) - var pathParts [1]string - pathParts[0] = "/api/health" - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "GET", u) - if err != nil { - return res, errors.Wrap(err, "create request") - } - - stage = "SendRequest" - resp, err := c.cfg.Client.Do(r) - if err != nil { - return res, errors.Wrap(err, "do request") - } - defer resp.Body.Close() - - stage = "DecodeResponse" - result, err := decodeGetHealthResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} - -// HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. -// -// Heartbeat telegram account. -// -// GET /api/telegram/account/heartbeat/{token} -func (c *Client) HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error { - _, err := c.sendHeartbeatTelegramAccount(ctx, params) - return err -} - -func (c *Client) sendHeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) (res *HeartbeatTelegramAccountOK, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("heartbeatTelegramAccount"), - semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/api/telegram/account/heartbeat/{token}"), - } - - // Run stopwatch. - startTime := time.Now() - defer func() { - // Use floating point division here for higher precision (instead of Millisecond method). - elapsedDuration := time.Since(startTime) - c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) - }() - - // Increment request counter. - c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - - // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, HeartbeatTelegramAccountOperation, - trace.WithAttributes(otelAttrs...), - clientSpanKind, - ) - // Track stage for error reporting. - var stage string - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, stage) - c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - } - span.End() - }() - - stage = "BuildURL" - u := uri.Clone(c.requestURL(ctx)) - var pathParts [2]string - pathParts[0] = "/api/telegram/account/heartbeat/" - { - // Encode "token" parameter. - e := uri.NewPathEncoder(uri.PathEncoderConfig{ - Param: "token", - Style: uri.PathStyleSimple, - Explode: false, - }) - if err := func() error { - return e.EncodeValue(conv.UUIDToString(params.Token)) - }(); err != nil { - return res, errors.Wrap(err, "encode path") - } - encoded, err := e.Result() - if err != nil { - return res, errors.Wrap(err, "encode path") - } - pathParts[1] = encoded - } - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeQueryParams" - q := uri.NewQueryEncoder() - { - // Encode "forget" parameter. - cfg := uri.QueryParameterEncodingConfig{ - Name: "forget", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - if val, ok := params.Forget.Get(); ok { - return e.EncodeValue(conv.BoolToString(val)) - } - return nil - }); err != nil { - return res, errors.Wrap(err, "encode query") - } - } - u.RawQuery = q.Values().Encode() - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "GET", u) - if err != nil { - return res, errors.Wrap(err, "create request") - } - - stage = "SendRequest" - resp, err := c.cfg.Client.Do(r) - if err != nil { - return res, errors.Wrap(err, "do request") - } - defer resp.Body.Close() - - stage = "DecodeResponse" - result, err := decodeHeartbeatTelegramAccountResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} - -// ReceiveTelegramCode invokes receiveTelegramCode operation. -// -// Receive telegram code. -// -// GET /api/telegram/code/receive/{token} -func (c *Client) ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) { - res, err := c.sendReceiveTelegramCode(ctx, params) - return res, err -} - -func (c *Client) sendReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (res *ReceiveTelegramCodeOK, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("receiveTelegramCode"), - semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/api/telegram/code/receive/{token}"), - } - - // Run stopwatch. - startTime := time.Now() - defer func() { - // Use floating point division here for higher precision (instead of Millisecond method). - elapsedDuration := time.Since(startTime) - c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) - }() - - // Increment request counter. - c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - - // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, ReceiveTelegramCodeOperation, - trace.WithAttributes(otelAttrs...), - clientSpanKind, - ) - // Track stage for error reporting. - var stage string - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, stage) - c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - } - span.End() - }() - - stage = "BuildURL" - u := uri.Clone(c.requestURL(ctx)) - var pathParts [2]string - pathParts[0] = "/api/telegram/code/receive/" - { - // Encode "token" parameter. - e := uri.NewPathEncoder(uri.PathEncoderConfig{ - Param: "token", - Style: uri.PathStyleSimple, - Explode: false, - }) - if err := func() error { - return e.EncodeValue(conv.UUIDToString(params.Token)) - }(); err != nil { - return res, errors.Wrap(err, "encode path") - } - encoded, err := e.Result() - if err != nil { - return res, errors.Wrap(err, "encode path") - } - pathParts[1] = encoded - } - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "GET", u) - if err != nil { - return res, errors.Wrap(err, "create request") - } - - stage = "SendRequest" - resp, err := c.cfg.Client.Do(r) - if err != nil { - return res, errors.Wrap(err, "do request") - } - defer resp.Body.Close() - - stage = "DecodeResponse" - result, err := decodeReceiveTelegramCodeResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} diff --git a/testutil/tgacc/oas_json_gen.go b/testutil/tgacc/oas_json_gen.go deleted file mode 100644 index 4792130b1..000000000 --- a/testutil/tgacc/oas_json_gen.go +++ /dev/null @@ -1,850 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "math/bits" - "strconv" - - "github.com/go-faster/errors" - "github.com/go-faster/jx" - - "github.com/ogen-go/ogen/json" - "github.com/ogen-go/ogen/validate" -) - -// Encode implements json.Marshaler. -func (s *AcquireTelegramAccountOK) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *AcquireTelegramAccountOK) encodeFields(e *jx.Encoder) { - { - e.FieldStart("account_id") - s.AccountID.Encode(e) - } - { - e.FieldStart("token") - json.EncodeUUID(e, s.Token) - } -} - -var jsonFieldsNameOfAcquireTelegramAccountOK = [2]string{ - 0: "account_id", - 1: "token", -} - -// Decode decodes AcquireTelegramAccountOK from json. -func (s *AcquireTelegramAccountOK) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode AcquireTelegramAccountOK to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "account_id": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - if err := s.AccountID.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"account_id\"") - } - case "token": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := json.DecodeUUID(d) - s.Token = v - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"token\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode AcquireTelegramAccountOK") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000011, - } { - if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { - // Mask only required fields and check equality to mask using XOR. - // - // If XOR result is not zero, result is not equal to expected, so some fields are missed. - // Bits of fields which would be set are actually bits of missed fields. - missed := bits.OnesCount8(result) - for bitN := 0; bitN < missed; bitN++ { - bitIdx := bits.TrailingZeros8(result) - fieldIdx := i*8 + bitIdx - var name string - if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountOK) { - name = jsonFieldsNameOfAcquireTelegramAccountOK[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *AcquireTelegramAccountOK) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *AcquireTelegramAccountOK) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *AcquireTelegramAccountReq) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *AcquireTelegramAccountReq) encodeFields(e *jx.Encoder) { - { - e.FieldStart("repo_owner") - e.Str(s.RepoOwner) - } - { - e.FieldStart("repo_name") - e.Str(s.RepoName) - } - { - e.FieldStart("job") - e.Str(s.Job) - } - { - e.FieldStart("run_id") - e.Int64(s.RunID) - } - { - e.FieldStart("run_attempt") - e.Int(s.RunAttempt) - } -} - -var jsonFieldsNameOfAcquireTelegramAccountReq = [5]string{ - 0: "repo_owner", - 1: "repo_name", - 2: "job", - 3: "run_id", - 4: "run_attempt", -} - -// Decode decodes AcquireTelegramAccountReq from json. -func (s *AcquireTelegramAccountReq) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode AcquireTelegramAccountReq to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "repo_owner": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.RepoOwner = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"repo_owner\"") - } - case "repo_name": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Str() - s.RepoName = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"repo_name\"") - } - case "job": - requiredBitSet[0] |= 1 << 2 - if err := func() error { - v, err := d.Str() - s.Job = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"job\"") - } - case "run_id": - requiredBitSet[0] |= 1 << 3 - if err := func() error { - v, err := d.Int64() - s.RunID = int64(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"run_id\"") - } - case "run_attempt": - requiredBitSet[0] |= 1 << 4 - if err := func() error { - v, err := d.Int() - s.RunAttempt = int(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"run_attempt\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode AcquireTelegramAccountReq") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00011111, - } { - if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { - // Mask only required fields and check equality to mask using XOR. - // - // If XOR result is not zero, result is not equal to expected, so some fields are missed. - // Bits of fields which would be set are actually bits of missed fields. - missed := bits.OnesCount8(result) - for bitN := 0; bitN < missed; bitN++ { - bitIdx := bits.TrailingZeros8(result) - fieldIdx := i*8 + bitIdx - var name string - if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountReq) { - name = jsonFieldsNameOfAcquireTelegramAccountReq[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *AcquireTelegramAccountReq) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *AcquireTelegramAccountReq) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *Error) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *Error) encodeFields(e *jx.Encoder) { - { - e.FieldStart("error_message") - e.Str(s.ErrorMessage) - } - { - if s.TraceID.Set { - e.FieldStart("trace_id") - s.TraceID.Encode(e) - } - } - { - if s.SpanID.Set { - e.FieldStart("span_id") - s.SpanID.Encode(e) - } - } -} - -var jsonFieldsNameOfError = [3]string{ - 0: "error_message", - 1: "trace_id", - 2: "span_id", -} - -// Decode decodes Error from json. -func (s *Error) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode Error to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "error_message": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.ErrorMessage = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"error_message\"") - } - case "trace_id": - if err := func() error { - s.TraceID.Reset() - if err := s.TraceID.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"trace_id\"") - } - case "span_id": - if err := func() error { - s.SpanID.Reset() - if err := s.SpanID.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"span_id\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode Error") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00000001, - } { - if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { - // Mask only required fields and check equality to mask using XOR. - // - // If XOR result is not zero, result is not equal to expected, so some fields are missed. - // Bits of fields which would be set are actually bits of missed fields. - missed := bits.OnesCount8(result) - for bitN := 0; bitN < missed; bitN++ { - bitIdx := bits.TrailingZeros8(result) - fieldIdx := i*8 + bitIdx - var name string - if fieldIdx < len(jsonFieldsNameOfError) { - name = jsonFieldsNameOfError[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *Error) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *Error) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *Health) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *Health) encodeFields(e *jx.Encoder) { - { - e.FieldStart("status") - e.Str(s.Status) - } - { - e.FieldStart("version") - e.Str(s.Version) - } - { - e.FieldStart("commit") - e.Str(s.Commit) - } - { - e.FieldStart("build_date") - json.EncodeDateTime(e, s.BuildDate) - } -} - -var jsonFieldsNameOfHealth = [4]string{ - 0: "status", - 1: "version", - 2: "commit", - 3: "build_date", -} - -// Decode decodes Health from json. -func (s *Health) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode Health to nil") - } - var requiredBitSet [1]uint8 - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "status": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.Status = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"status\"") - } - case "version": - requiredBitSet[0] |= 1 << 1 - if err := func() error { - v, err := d.Str() - s.Version = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"version\"") - } - case "commit": - requiredBitSet[0] |= 1 << 2 - if err := func() error { - v, err := d.Str() - s.Commit = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"commit\"") - } - case "build_date": - requiredBitSet[0] |= 1 << 3 - if err := func() error { - v, err := json.DecodeDateTime(d) - s.BuildDate = v - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"build_date\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode Health") - } - // Validate required fields. - var failures []validate.FieldError - for i, mask := range [1]uint8{ - 0b00001111, - } { - if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { - // Mask only required fields and check equality to mask using XOR. - // - // If XOR result is not zero, result is not equal to expected, so some fields are missed. - // Bits of fields which would be set are actually bits of missed fields. - missed := bits.OnesCount8(result) - for bitN := 0; bitN < missed; bitN++ { - bitIdx := bits.TrailingZeros8(result) - fieldIdx := i*8 + bitIdx - var name string - if fieldIdx < len(jsonFieldsNameOfHealth) { - name = jsonFieldsNameOfHealth[fieldIdx] - } else { - name = strconv.Itoa(fieldIdx) - } - failures = append(failures, validate.FieldError{ - Name: name, - Error: validate.ErrFieldRequired, - }) - // Reset bit. - result &^= 1 << bitIdx - } - } - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *Health) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *Health) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes SpanID as json. -func (o OptSpanID) Encode(e *jx.Encoder) { - if !o.Set { - return - } - o.Value.Encode(e) -} - -// Decode decodes SpanID from json. -func (o *OptSpanID) Decode(d *jx.Decoder) error { - if o == nil { - return errors.New("invalid: unable to decode OptSpanID to nil") - } - o.Set = true - if err := o.Value.Decode(d); err != nil { - return err - } - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s OptSpanID) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptSpanID) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes string as json. -func (o OptString) Encode(e *jx.Encoder) { - if !o.Set { - return - } - e.Str(string(o.Value)) -} - -// Decode decodes string from json. -func (o *OptString) Decode(d *jx.Decoder) error { - if o == nil { - return errors.New("invalid: unable to decode OptString to nil") - } - o.Set = true - v, err := d.Str() - if err != nil { - return err - } - o.Value = string(v) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s OptString) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptString) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes TraceID as json. -func (o OptTraceID) Encode(e *jx.Encoder) { - if !o.Set { - return - } - o.Value.Encode(e) -} - -// Decode decodes TraceID from json. -func (o *OptTraceID) Decode(d *jx.Decoder) error { - if o == nil { - return errors.New("invalid: unable to decode OptTraceID to nil") - } - o.Set = true - if err := o.Value.Decode(d); err != nil { - return err - } - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s OptTraceID) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptTraceID) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode implements json.Marshaler. -func (s *ReceiveTelegramCodeOK) Encode(e *jx.Encoder) { - e.ObjStart() - s.encodeFields(e) - e.ObjEnd() -} - -// encodeFields encodes fields. -func (s *ReceiveTelegramCodeOK) encodeFields(e *jx.Encoder) { - { - if s.Code.Set { - e.FieldStart("code") - s.Code.Encode(e) - } - } -} - -var jsonFieldsNameOfReceiveTelegramCodeOK = [1]string{ - 0: "code", -} - -// Decode decodes ReceiveTelegramCodeOK from json. -func (s *ReceiveTelegramCodeOK) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode ReceiveTelegramCodeOK to nil") - } - - if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { - switch string(k) { - case "code": - if err := func() error { - s.Code.Reset() - if err := s.Code.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"code\"") - } - default: - return d.Skip() - } - return nil - }); err != nil { - return errors.Wrap(err, "decode ReceiveTelegramCodeOK") - } - - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s *ReceiveTelegramCodeOK) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ReceiveTelegramCodeOK) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes SpanID as json. -func (s SpanID) Encode(e *jx.Encoder) { - unwrapped := string(s) - - e.Str(unwrapped) -} - -// Decode decodes SpanID from json. -func (s *SpanID) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode SpanID to nil") - } - var unwrapped string - if err := func() error { - v, err := d.Str() - unwrapped = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "alias") - } - *s = SpanID(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s SpanID) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *SpanID) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes TelegramAccountID as json. -func (s TelegramAccountID) Encode(e *jx.Encoder) { - unwrapped := string(s) - - e.Str(unwrapped) -} - -// Decode decodes TelegramAccountID from json. -func (s *TelegramAccountID) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode TelegramAccountID to nil") - } - var unwrapped string - if err := func() error { - v, err := d.Str() - unwrapped = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "alias") - } - *s = TelegramAccountID(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s TelegramAccountID) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *TelegramAccountID) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} - -// Encode encodes TraceID as json. -func (s TraceID) Encode(e *jx.Encoder) { - unwrapped := string(s) - - e.Str(unwrapped) -} - -// Decode decodes TraceID from json. -func (s *TraceID) Decode(d *jx.Decoder) error { - if s == nil { - return errors.New("invalid: unable to decode TraceID to nil") - } - var unwrapped string - if err := func() error { - v, err := d.Str() - unwrapped = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "alias") - } - *s = TraceID(unwrapped) - return nil -} - -// MarshalJSON implements stdjson.Marshaler. -func (s TraceID) MarshalJSON() ([]byte, error) { - e := jx.Encoder{} - s.Encode(&e) - return e.Bytes(), nil -} - -// UnmarshalJSON implements stdjson.Unmarshaler. -func (s *TraceID) UnmarshalJSON(data []byte) error { - d := jx.DecodeBytes(data) - return s.Decode(d) -} diff --git a/testutil/tgacc/oas_operations_gen.go b/testutil/tgacc/oas_operations_gen.go deleted file mode 100644 index 25b935d34..000000000 --- a/testutil/tgacc/oas_operations_gen.go +++ /dev/null @@ -1,13 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -// OperationName is the ogen operation name -type OperationName = string - -const ( - AcquireTelegramAccountOperation OperationName = "AcquireTelegramAccount" - GetHealthOperation OperationName = "GetHealth" - HeartbeatTelegramAccountOperation OperationName = "HeartbeatTelegramAccount" - ReceiveTelegramCodeOperation OperationName = "ReceiveTelegramCode" -) diff --git a/testutil/tgacc/oas_parameters_gen.go b/testutil/tgacc/oas_parameters_gen.go deleted file mode 100644 index 4ebb7014c..000000000 --- a/testutil/tgacc/oas_parameters_gen.go +++ /dev/null @@ -1,18 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "github.com/google/uuid" -) - -// HeartbeatTelegramAccountParams is parameters of heartbeatTelegramAccount operation. -type HeartbeatTelegramAccountParams struct { - Token uuid.UUID - Forget OptBool -} - -// ReceiveTelegramCodeParams is parameters of receiveTelegramCode operation. -type ReceiveTelegramCodeParams struct { - Token uuid.UUID -} diff --git a/testutil/tgacc/oas_request_encoders_gen.go b/testutil/tgacc/oas_request_encoders_gen.go deleted file mode 100644 index c55309923..000000000 --- a/testutil/tgacc/oas_request_encoders_gen.go +++ /dev/null @@ -1,26 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "bytes" - "net/http" - - "github.com/go-faster/jx" - - ht "github.com/ogen-go/ogen/http" -) - -func encodeAcquireTelegramAccountRequest( - req *AcquireTelegramAccountReq, - r *http.Request, -) error { - const contentType = "application/json" - e := new(jx.Encoder) - { - req.Encode(e) - } - encoded := e.Bytes() - ht.SetBody(r, bytes.NewReader(encoded), contentType) - return nil -} diff --git a/testutil/tgacc/oas_response_decoders_gen.go b/testutil/tgacc/oas_response_decoders_gen.go deleted file mode 100644 index 1d4d1dc54..000000000 --- a/testutil/tgacc/oas_response_decoders_gen.go +++ /dev/null @@ -1,369 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "io" - "mime" - "net/http" - - "github.com/go-faster/errors" - "github.com/go-faster/jx" - - "github.com/ogen-go/ogen/ogenerrors" - "github.com/ogen-go/ogen/validate" -) - -func decodeAcquireTelegramAccountResponse(resp *http.Response) (res *AcquireTelegramAccountOK, _ error) { - switch resp.StatusCode { - case 200: - // Code 200. - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response AcquireTelegramAccountOK - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &response, nil - default: - return res, validate.InvalidContentType(ct) - } - } - // Convenient error response. - defRes, err := func() (res *ErrorStatusCode, err error) { - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response Error - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &ErrorStatusCode{ - StatusCode: resp.StatusCode, - Response: response, - }, nil - default: - return res, validate.InvalidContentType(ct) - } - }() - if err != nil { - return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) - } - return res, errors.Wrap(defRes, "error") -} - -func decodeGetHealthResponse(resp *http.Response) (res *Health, _ error) { - switch resp.StatusCode { - case 200: - // Code 200. - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response Health - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - return &response, nil - default: - return res, validate.InvalidContentType(ct) - } - } - // Convenient error response. - defRes, err := func() (res *ErrorStatusCode, err error) { - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response Error - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &ErrorStatusCode{ - StatusCode: resp.StatusCode, - Response: response, - }, nil - default: - return res, validate.InvalidContentType(ct) - } - }() - if err != nil { - return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) - } - return res, errors.Wrap(defRes, "error") -} - -func decodeHeartbeatTelegramAccountResponse(resp *http.Response) (res *HeartbeatTelegramAccountOK, _ error) { - switch resp.StatusCode { - case 200: - // Code 200. - return &HeartbeatTelegramAccountOK{}, nil - } - // Convenient error response. - defRes, err := func() (res *ErrorStatusCode, err error) { - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response Error - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &ErrorStatusCode{ - StatusCode: resp.StatusCode, - Response: response, - }, nil - default: - return res, validate.InvalidContentType(ct) - } - }() - if err != nil { - return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) - } - return res, errors.Wrap(defRes, "error") -} - -func decodeReceiveTelegramCodeResponse(resp *http.Response) (res *ReceiveTelegramCodeOK, _ error) { - switch resp.StatusCode { - case 200: - // Code 200. - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response ReceiveTelegramCodeOK - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &response, nil - default: - return res, validate.InvalidContentType(ct) - } - } - // Convenient error response. - defRes, err := func() (res *ErrorStatusCode, err error) { - ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) - if err != nil { - return res, errors.Wrap(err, "parse media type") - } - switch { - case ct == "application/json": - buf, err := io.ReadAll(resp.Body) - if err != nil { - return res, err - } - d := jx.DecodeBytes(buf) - - var response Error - if err := func() error { - if err := response.Decode(d); err != nil { - return err - } - if err := d.Skip(); err != io.EOF { - return errors.New("unexpected trailing data") - } - return nil - }(); err != nil { - err = &ogenerrors.DecodeBodyError{ - ContentType: ct, - Body: buf, - Err: err, - } - return res, err - } - // Validate response. - if err := func() error { - if err := response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } - return &ErrorStatusCode{ - StatusCode: resp.StatusCode, - Response: response, - }, nil - default: - return res, validate.InvalidContentType(ct) - } - }() - if err != nil { - return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) - } - return res, errors.Wrap(defRes, "error") -} diff --git a/testutil/tgacc/oas_schemas_gen.go b/testutil/tgacc/oas_schemas_gen.go deleted file mode 100644 index e07bfe699..000000000 --- a/testutil/tgacc/oas_schemas_gen.go +++ /dev/null @@ -1,440 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "fmt" - "time" - - "github.com/google/uuid" -) - -func (s *ErrorStatusCode) Error() string { - return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) -} - -type AcquireTelegramAccountOK struct { - AccountID TelegramAccountID `json:"account_id"` - // Access token. - Token uuid.UUID `json:"token"` -} - -// GetAccountID returns the value of AccountID. -func (s *AcquireTelegramAccountOK) GetAccountID() TelegramAccountID { - return s.AccountID -} - -// GetToken returns the value of Token. -func (s *AcquireTelegramAccountOK) GetToken() uuid.UUID { - return s.Token -} - -// SetAccountID sets the value of AccountID. -func (s *AcquireTelegramAccountOK) SetAccountID(val TelegramAccountID) { - s.AccountID = val -} - -// SetToken sets the value of Token. -func (s *AcquireTelegramAccountOK) SetToken(val uuid.UUID) { - s.Token = val -} - -type AcquireTelegramAccountReq struct { - // Repository owner. - RepoOwner string `json:"repo_owner"` - // Repository name. - RepoName string `json:"repo_name"` - // Job ID. - Job string `json:"job"` - RunID int64 `json:"run_id"` - RunAttempt int `json:"run_attempt"` -} - -// GetRepoOwner returns the value of RepoOwner. -func (s *AcquireTelegramAccountReq) GetRepoOwner() string { - return s.RepoOwner -} - -// GetRepoName returns the value of RepoName. -func (s *AcquireTelegramAccountReq) GetRepoName() string { - return s.RepoName -} - -// GetJob returns the value of Job. -func (s *AcquireTelegramAccountReq) GetJob() string { - return s.Job -} - -// GetRunID returns the value of RunID. -func (s *AcquireTelegramAccountReq) GetRunID() int64 { - return s.RunID -} - -// GetRunAttempt returns the value of RunAttempt. -func (s *AcquireTelegramAccountReq) GetRunAttempt() int { - return s.RunAttempt -} - -// SetRepoOwner sets the value of RepoOwner. -func (s *AcquireTelegramAccountReq) SetRepoOwner(val string) { - s.RepoOwner = val -} - -// SetRepoName sets the value of RepoName. -func (s *AcquireTelegramAccountReq) SetRepoName(val string) { - s.RepoName = val -} - -// SetJob sets the value of Job. -func (s *AcquireTelegramAccountReq) SetJob(val string) { - s.Job = val -} - -// SetRunID sets the value of RunID. -func (s *AcquireTelegramAccountReq) SetRunID(val int64) { - s.RunID = val -} - -// SetRunAttempt sets the value of RunAttempt. -func (s *AcquireTelegramAccountReq) SetRunAttempt(val int) { - s.RunAttempt = val -} - -// Error occurred while processing request. -// Ref: #/components/schemas/Error -type Error struct { - // Human-readable error message. - ErrorMessage string `json:"error_message"` - TraceID OptTraceID `json:"trace_id"` - SpanID OptSpanID `json:"span_id"` -} - -// GetErrorMessage returns the value of ErrorMessage. -func (s *Error) GetErrorMessage() string { - return s.ErrorMessage -} - -// GetTraceID returns the value of TraceID. -func (s *Error) GetTraceID() OptTraceID { - return s.TraceID -} - -// GetSpanID returns the value of SpanID. -func (s *Error) GetSpanID() OptSpanID { - return s.SpanID -} - -// SetErrorMessage sets the value of ErrorMessage. -func (s *Error) SetErrorMessage(val string) { - s.ErrorMessage = val -} - -// SetTraceID sets the value of TraceID. -func (s *Error) SetTraceID(val OptTraceID) { - s.TraceID = val -} - -// SetSpanID sets the value of SpanID. -func (s *Error) SetSpanID(val OptSpanID) { - s.SpanID = val -} - -// ErrorStatusCode wraps Error with StatusCode. -type ErrorStatusCode struct { - StatusCode int - Response Error -} - -// GetStatusCode returns the value of StatusCode. -func (s *ErrorStatusCode) GetStatusCode() int { - return s.StatusCode -} - -// GetResponse returns the value of Response. -func (s *ErrorStatusCode) GetResponse() Error { - return s.Response -} - -// SetStatusCode sets the value of StatusCode. -func (s *ErrorStatusCode) SetStatusCode(val int) { - s.StatusCode = val -} - -// SetResponse sets the value of Response. -func (s *ErrorStatusCode) SetResponse(val Error) { - s.Response = val -} - -// Ref: #/components/schemas/Health -type Health struct { - // Health status. - Status string `json:"status"` - // Service version. - Version string `json:"version"` - // Service commit. - Commit string `json:"commit"` - // Service build date. - BuildDate time.Time `json:"build_date"` -} - -// GetStatus returns the value of Status. -func (s *Health) GetStatus() string { - return s.Status -} - -// GetVersion returns the value of Version. -func (s *Health) GetVersion() string { - return s.Version -} - -// GetCommit returns the value of Commit. -func (s *Health) GetCommit() string { - return s.Commit -} - -// GetBuildDate returns the value of BuildDate. -func (s *Health) GetBuildDate() time.Time { - return s.BuildDate -} - -// SetStatus sets the value of Status. -func (s *Health) SetStatus(val string) { - s.Status = val -} - -// SetVersion sets the value of Version. -func (s *Health) SetVersion(val string) { - s.Version = val -} - -// SetCommit sets the value of Commit. -func (s *Health) SetCommit(val string) { - s.Commit = val -} - -// SetBuildDate sets the value of BuildDate. -func (s *Health) SetBuildDate(val time.Time) { - s.BuildDate = val -} - -// HeartbeatTelegramAccountOK is response for HeartbeatTelegramAccount operation. -type HeartbeatTelegramAccountOK struct{} - -// NewOptBool returns new OptBool with value set to v. -func NewOptBool(v bool) OptBool { - return OptBool{ - Value: v, - Set: true, - } -} - -// OptBool is optional bool. -type OptBool struct { - Value bool - Set bool -} - -// IsSet returns true if OptBool was set. -func (o OptBool) IsSet() bool { return o.Set } - -// Reset unsets value. -func (o *OptBool) Reset() { - var v bool - o.Value = v - o.Set = false -} - -// SetTo sets value to v. -func (o *OptBool) SetTo(v bool) { - o.Set = true - o.Value = v -} - -// Get returns value and boolean that denotes whether value was set. -func (o OptBool) Get() (v bool, ok bool) { - if !o.Set { - return v, false - } - return o.Value, true -} - -// Or returns value if set, or given parameter if does not. -func (o OptBool) Or(d bool) bool { - if v, ok := o.Get(); ok { - return v - } - return d -} - -// NewOptSpanID returns new OptSpanID with value set to v. -func NewOptSpanID(v SpanID) OptSpanID { - return OptSpanID{ - Value: v, - Set: true, - } -} - -// OptSpanID is optional SpanID. -type OptSpanID struct { - Value SpanID - Set bool -} - -// IsSet returns true if OptSpanID was set. -func (o OptSpanID) IsSet() bool { return o.Set } - -// Reset unsets value. -func (o *OptSpanID) Reset() { - var v SpanID - o.Value = v - o.Set = false -} - -// SetTo sets value to v. -func (o *OptSpanID) SetTo(v SpanID) { - o.Set = true - o.Value = v -} - -// Get returns value and boolean that denotes whether value was set. -func (o OptSpanID) Get() (v SpanID, ok bool) { - if !o.Set { - return v, false - } - return o.Value, true -} - -// Or returns value if set, or given parameter if does not. -func (o OptSpanID) Or(d SpanID) SpanID { - if v, ok := o.Get(); ok { - return v - } - return d -} - -// NewOptString returns new OptString with value set to v. -func NewOptString(v string) OptString { - return OptString{ - Value: v, - Set: true, - } -} - -// OptString is optional string. -type OptString struct { - Value string - Set bool -} - -// IsSet returns true if OptString was set. -func (o OptString) IsSet() bool { return o.Set } - -// Reset unsets value. -func (o *OptString) Reset() { - var v string - o.Value = v - o.Set = false -} - -// SetTo sets value to v. -func (o *OptString) SetTo(v string) { - o.Set = true - o.Value = v -} - -// Get returns value and boolean that denotes whether value was set. -func (o OptString) Get() (v string, ok bool) { - if !o.Set { - return v, false - } - return o.Value, true -} - -// Or returns value if set, or given parameter if does not. -func (o OptString) Or(d string) string { - if v, ok := o.Get(); ok { - return v - } - return d -} - -// NewOptTraceID returns new OptTraceID with value set to v. -func NewOptTraceID(v TraceID) OptTraceID { - return OptTraceID{ - Value: v, - Set: true, - } -} - -// OptTraceID is optional TraceID. -type OptTraceID struct { - Value TraceID - Set bool -} - -// IsSet returns true if OptTraceID was set. -func (o OptTraceID) IsSet() bool { return o.Set } - -// Reset unsets value. -func (o *OptTraceID) Reset() { - var v TraceID - o.Value = v - o.Set = false -} - -// SetTo sets value to v. -func (o *OptTraceID) SetTo(v TraceID) { - o.Set = true - o.Value = v -} - -// Get returns value and boolean that denotes whether value was set. -func (o OptTraceID) Get() (v TraceID, ok bool) { - if !o.Set { - return v, false - } - return o.Value, true -} - -// Or returns value if set, or given parameter if does not. -func (o OptTraceID) Or(d TraceID) TraceID { - if v, ok := o.Get(); ok { - return v - } - return d -} - -type ReceiveTelegramCodeOK struct { - // Code. - Code OptString `json:"code"` -} - -// GetCode returns the value of Code. -func (s *ReceiveTelegramCodeOK) GetCode() OptString { - return s.Code -} - -// SetCode sets the value of Code. -func (s *ReceiveTelegramCodeOK) SetCode(val OptString) { - s.Code = val -} - -type SpanID string - -type TelegramAccountID string - -type TokenAuth struct { - APIKey string -} - -// GetAPIKey returns the value of APIKey. -func (s *TokenAuth) GetAPIKey() string { - return s.APIKey -} - -// SetAPIKey sets the value of APIKey. -func (s *TokenAuth) SetAPIKey(val string) { - s.APIKey = val -} - -type TraceID string diff --git a/testutil/tgacc/oas_security_gen.go b/testutil/tgacc/oas_security_gen.go deleted file mode 100644 index 489ab849f..000000000 --- a/testutil/tgacc/oas_security_gen.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "context" - "net/http" - - "github.com/go-faster/errors" -) - -// SecuritySource is provider of security values (tokens, passwords, etc.). -type SecuritySource interface { - // TokenAuth provides tokenAuth security value. - TokenAuth(ctx context.Context, operationName OperationName) (TokenAuth, error) -} - -func (s *Client) securityTokenAuth(ctx context.Context, operationName OperationName, req *http.Request) error { - t, err := s.sec.TokenAuth(ctx, operationName) - if err != nil { - return errors.Wrap(err, "security source \"TokenAuth\"") - } - req.Header.Set("Token", t.APIKey) - return nil -} diff --git a/testutil/tgacc/oas_validators_gen.go b/testutil/tgacc/oas_validators_gen.go deleted file mode 100644 index a7add8830..000000000 --- a/testutil/tgacc/oas_validators_gen.go +++ /dev/null @@ -1,189 +0,0 @@ -// Code generated by ogen, DO NOT EDIT. - -package tgacc - -import ( - "github.com/go-faster/errors" - - "github.com/ogen-go/ogen/validate" -) - -func (s *AcquireTelegramAccountOK) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if err := s.AccountID.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "account_id", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s *Error) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if value, ok := s.TraceID.Get(); ok { - if err := func() error { - if err := value.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "trace_id", - Error: err, - }) - } - if err := func() error { - if value, ok := s.SpanID.Get(); ok { - if err := func() error { - if err := value.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "span_id", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s *ErrorStatusCode) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if err := s.Response.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "Response", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s *ReceiveTelegramCodeOK) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if value, ok := s.Code.Get(); ok { - if err := func() error { - if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 0, - MaxLengthSet: false, - Email: false, - Hostname: false, - Regex: regexMap["^[0-9]{3,6}$"], - }).Validate(string(value)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "code", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - -func (s SpanID) Validate() error { - alias := (string)(s) - if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 0, - MaxLengthSet: false, - Email: false, - Hostname: false, - Regex: regexMap["[[:xdigit:]]{16}"], - }).Validate(string(alias)); err != nil { - return errors.Wrap(err, "string") - } - return nil -} - -func (s TelegramAccountID) Validate() error { - alias := (string)(s) - if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 0, - MaxLengthSet: false, - Email: false, - Hostname: false, - Regex: regexMap["^[0-9]{7,15}$"], - }).Validate(string(alias)); err != nil { - return errors.Wrap(err, "string") - } - return nil -} - -func (s TraceID) Validate() error { - alias := (string)(s) - if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 0, - MaxLengthSet: false, - Email: false, - Hostname: false, - Regex: regexMap["[[:xdigit:]]{32}"], - }).Validate(string(alias)); err != nil { - return errors.Wrap(err, "string") - } - return nil -} diff --git a/testutil/.ogen.yml b/tgacc/.ogen.yml similarity index 100% rename from testutil/.ogen.yml rename to tgacc/.ogen.yml diff --git a/tgacc/generate.go b/tgacc/generate.go new file mode 100644 index 000000000..23091a007 --- /dev/null +++ b/tgacc/generate.go @@ -0,0 +1,3 @@ +package tgacc + +//go:generate go run -mod=mod github.com/ogen-go/ogen/cmd/ogen --target oas --package oas --clean tgacc.openapi.yaml diff --git a/testutil/tgacc.go b/tgacc/tgacc.go similarity index 82% rename from testutil/tgacc.go rename to tgacc/tgacc.go index 93fba58d5..01532f2b8 100644 --- a/testutil/tgacc.go +++ b/tgacc/tgacc.go @@ -1,4 +1,4 @@ -package testutil +package tgacc import ( "context" @@ -11,13 +11,13 @@ import ( "github.com/google/uuid" "github.com/gotd/td/telegram/auth" - "github.com/gotd/td/testutil/tgacc" "github.com/gotd/td/tg" + "github.com/gotd/td/tgacc/oas" ) // TestAccountManager is external test account manager. type TestAccountManager struct { - client *tgacc.Client + client *oas.Client } func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) { @@ -30,7 +30,7 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) return nil, errors.New("GITHUB_RUN_ID is empty") } attempt, _ := strconv.Atoi(os.Getenv("GITHUB_RUN_ATTEMPT")) - res, err := t.client.AcquireTelegramAccount(ctx, &tgacc.AcquireTelegramAccountReq{ + res, err := t.client.AcquireTelegramAccount(ctx, &oas.AcquireTelegramAccountReq{ RepoOwner: "gotd", RepoName: "td", Job: jobID, @@ -57,8 +57,8 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) type ghSecuritySource struct{} -func (s ghSecuritySource) TokenAuth(ctx context.Context, operationName tgacc.OperationName) (tgacc.TokenAuth, error) { - return tgacc.TokenAuth{ +func (s ghSecuritySource) TokenAuth(ctx context.Context, operationName oas.OperationName) (oas.TokenAuth, error) { + return oas.TokenAuth{ APIKey: os.Getenv("GITHUB_TOKEN"), }, nil } @@ -68,16 +68,16 @@ type TestAccount struct { UserAuthenticator auth.UserAuthenticator token uuid.UUID - client *tgacc.Client + client *oas.Client } // Close releases telegram account. func (t TestAccount) Close() error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - return t.client.HeartbeatTelegramAccount(ctx, tgacc.HeartbeatTelegramAccountParams{ + return t.client.HeartbeatTelegramAccount(ctx, oas.HeartbeatTelegramAccountParams{ Token: t.token, - Forget: tgacc.NewOptBool(true), + Forget: oas.NewOptBool(true), }) } @@ -86,7 +86,7 @@ func (t TestAccount) Close() error { type codeAuth struct { phone string token uuid.UUID - client *tgacc.Client + client *oas.Client } func (codeAuth) SignUp(ctx context.Context) (auth.UserInfo, error) { @@ -111,7 +111,7 @@ func (a codeAuth) Code(ctx context.Context, sentCode *tg.AuthSentCode) (string, bo.MaxInterval = time.Second return backoff.RetryWithData(func() (string, error) { - res, err := a.client.ReceiveTelegramCode(ctx, tgacc.ReceiveTelegramCodeParams{ + res, err := a.client.ReceiveTelegramCode(ctx, oas.ReceiveTelegramCodeParams{ Token: a.token, }) if err != nil { @@ -125,7 +125,7 @@ func (a codeAuth) Code(ctx context.Context, sentCode *tg.AuthSentCode) (string, } func NewTestAccountManager() (*TestAccountManager, error) { - client, err := tgacc.NewClient("https://bot.gotd.dev", ghSecuritySource{}) + client, err := oas.NewClient("https://bot.gotd.dev", ghSecuritySource{}) if err != nil { return nil, errors.Wrap(err, "create client") } diff --git a/testutil/tgacc.openapi.yaml b/tgacc/tgacc.openapi.yaml similarity index 100% rename from testutil/tgacc.openapi.yaml rename to tgacc/tgacc.openapi.yaml diff --git a/testutil/tgacc_test.go b/tgacc/tgacc_test.go similarity index 82% rename from testutil/tgacc_test.go rename to tgacc/tgacc_test.go index c8b4f114c..b737154ce 100644 --- a/testutil/tgacc_test.go +++ b/tgacc/tgacc_test.go @@ -1,14 +1,16 @@ -package testutil +package tgacc import ( "context" "testing" "github.com/stretchr/testify/require" + + "github.com/gotd/td/testutil" ) func TestExternalE2E(t *testing.T) { - SkipExternal(t) + testutil.SkipExternal(t) manager, err := NewTestAccountManager() require.NoError(t, err) From 49250f5527106d5cbf8296d43cb1adc20a6be132 Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:49:07 +0300 Subject: [PATCH 05/11] chore: add missing files --- tgacc/oas/oas_cfg_gen.go | 143 +++++ tgacc/oas/oas_client_gen.go | 478 ++++++++++++++ tgacc/oas/oas_json_gen.go | 850 +++++++++++++++++++++++++ tgacc/oas/oas_operations_gen.go | 13 + tgacc/oas/oas_parameters_gen.go | 18 + tgacc/oas/oas_request_encoders_gen.go | 26 + tgacc/oas/oas_response_decoders_gen.go | 369 +++++++++++ tgacc/oas/oas_schemas_gen.go | 440 +++++++++++++ tgacc/oas/oas_security_gen.go | 25 + tgacc/oas/oas_validators_gen.go | 189 ++++++ 10 files changed, 2551 insertions(+) create mode 100644 tgacc/oas/oas_cfg_gen.go create mode 100644 tgacc/oas/oas_client_gen.go create mode 100644 tgacc/oas/oas_json_gen.go create mode 100644 tgacc/oas/oas_operations_gen.go create mode 100644 tgacc/oas/oas_parameters_gen.go create mode 100644 tgacc/oas/oas_request_encoders_gen.go create mode 100644 tgacc/oas/oas_response_decoders_gen.go create mode 100644 tgacc/oas/oas_schemas_gen.go create mode 100644 tgacc/oas/oas_security_gen.go create mode 100644 tgacc/oas/oas_validators_gen.go diff --git a/tgacc/oas/oas_cfg_gen.go b/tgacc/oas/oas_cfg_gen.go new file mode 100644 index 000000000..8b4059e7f --- /dev/null +++ b/tgacc/oas/oas_cfg_gen.go @@ -0,0 +1,143 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "net/http" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/ogenregex" + "github.com/ogen-go/ogen/otelogen" +) + +var regexMap = map[string]ogenregex.Regexp{ + "[[:xdigit:]]{16}": ogenregex.MustCompile("[[:xdigit:]]{16}"), + "[[:xdigit:]]{32}": ogenregex.MustCompile("[[:xdigit:]]{32}"), + "^[0-9]{3,6}$": ogenregex.MustCompile("^[0-9]{3,6}$"), + "^[0-9]{7,15}$": ogenregex.MustCompile("^[0-9]{7,15}$"), +} +var ( + // Allocate option closure once. + clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) +) + +type ( + optionFunc[C any] func(*C) + otelOptionFunc func(*otelConfig) +) + +type otelConfig struct { + TracerProvider trace.TracerProvider + Tracer trace.Tracer + MeterProvider metric.MeterProvider + Meter metric.Meter +} + +func (cfg *otelConfig) initOTEL() { + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + if cfg.MeterProvider == nil { + cfg.MeterProvider = otel.GetMeterProvider() + } + cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, + trace.WithInstrumentationVersion(otelogen.SemVersion()), + ) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name, + metric.WithInstrumentationVersion(otelogen.SemVersion()), + ) +} + +type clientConfig struct { + otelConfig + Client ht.Client +} + +// ClientOption is client config option. +type ClientOption interface { + applyClient(*clientConfig) +} + +var _ ClientOption = (optionFunc[clientConfig])(nil) + +func (o optionFunc[C]) applyClient(c *C) { + o(c) +} + +var _ ClientOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyClient(c *clientConfig) { + o(&c.otelConfig) +} + +func newClientConfig(opts ...ClientOption) clientConfig { + cfg := clientConfig{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt.applyClient(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseClient struct { + cfg clientConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (cfg clientConfig) baseClient() (c baseClient, err error) { + c = baseClient{cfg: cfg} + if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil { + return c, err + } + return c, nil +} + +// Option is config option. +type Option interface { + ClientOption +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +// +// If none is specified, the global provider is used. +func WithTracerProvider(provider trace.TracerProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.TracerProvider = provider + } + }) +} + +// WithMeterProvider specifies a meter provider to use for creating a meter. +// +// If none is specified, the otel.GetMeterProvider() is used. +func WithMeterProvider(provider metric.MeterProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.MeterProvider = provider + } + }) +} + +// WithClient specifies http client to use. +func WithClient(client ht.Client) ClientOption { + return optionFunc[clientConfig](func(cfg *clientConfig) { + if client != nil { + cfg.Client = client + } + }) +} diff --git a/tgacc/oas/oas_client_gen.go b/tgacc/oas/oas_client_gen.go new file mode 100644 index 000000000..b7d60c603 --- /dev/null +++ b/tgacc/oas/oas_client_gen.go @@ -0,0 +1,478 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "go.opentelemetry.io/otel/trace" + + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" + "github.com/ogen-go/ogen/uri" +) + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // AcquireTelegramAccount invokes acquireTelegramAccount operation. + // + // Acquire telegram account. + // + // POST /api/telegram/account/acquire + AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) + // GetHealth invokes getHealth operation. + // + // Get health. + // + // GET /api/health + GetHealth(ctx context.Context) (*Health, error) + // HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. + // + // Heartbeat telegram account. + // + // GET /api/telegram/account/heartbeat/{token} + HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error + // ReceiveTelegramCode invokes receiveTelegramCode operation. + // + // Receive telegram code. + // + // GET /api/telegram/code/receive/{token} + ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) +} + +// Client implements OAS client. +type Client struct { + serverURL *url.URL + sec SecuritySource + baseClient +} + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// NewClient initializes new Client defined by OAS. +func NewClient(serverURL string, sec SecuritySource, opts ...ClientOption) (*Client, error) { + u, err := url.Parse(serverURL) + if err != nil { + return nil, err + } + trimTrailingSlashes(u) + + c, err := newClientConfig(opts...).baseClient() + if err != nil { + return nil, err + } + return &Client{ + serverURL: u, + sec: sec, + baseClient: c, + }, nil +} + +type serverURLKey struct{} + +// WithServerURL sets context key to override server URL. +func WithServerURL(ctx context.Context, u *url.URL) context.Context { + return context.WithValue(ctx, serverURLKey{}, u) +} + +func (c *Client) requestURL(ctx context.Context) *url.URL { + u, ok := ctx.Value(serverURLKey{}).(*url.URL) + if !ok { + return c.serverURL + } + return u +} + +// AcquireTelegramAccount invokes acquireTelegramAccount operation. +// +// Acquire telegram account. +// +// POST /api/telegram/account/acquire +func (c *Client) AcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (*AcquireTelegramAccountOK, error) { + res, err := c.sendAcquireTelegramAccount(ctx, request) + return res, err +} + +func (c *Client) sendAcquireTelegramAccount(ctx context.Context, request *AcquireTelegramAccountReq) (res *AcquireTelegramAccountOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("acquireTelegramAccount"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/api/telegram/account/acquire"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, AcquireTelegramAccountOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/api/telegram/account/acquire" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeAcquireTelegramAccountRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + { + type bitset = [1]uint8 + var satisfied bitset + { + stage = "Security:TokenAuth" + switch err := c.securityTokenAuth(ctx, AcquireTelegramAccountOperation, r); { + case err == nil: // if NO error + satisfied[0] |= 1 << 0 + case errors.Is(err, ogenerrors.ErrSkipClientSecurity): + // Skip this security. + default: + return res, errors.Wrap(err, "security \"TokenAuth\"") + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied + } + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeAcquireTelegramAccountResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// GetHealth invokes getHealth operation. +// +// Get health. +// +// GET /api/health +func (c *Client) GetHealth(ctx context.Context) (*Health, error) { + res, err := c.sendGetHealth(ctx) + return res, err +} + +func (c *Client) sendGetHealth(ctx context.Context) (res *Health, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getHealth"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/health"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, GetHealthOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/api/health" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGetHealthResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// HeartbeatTelegramAccount invokes heartbeatTelegramAccount operation. +// +// Heartbeat telegram account. +// +// GET /api/telegram/account/heartbeat/{token} +func (c *Client) HeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) error { + _, err := c.sendHeartbeatTelegramAccount(ctx, params) + return err +} + +func (c *Client) sendHeartbeatTelegramAccount(ctx context.Context, params HeartbeatTelegramAccountParams) (res *HeartbeatTelegramAccountOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("heartbeatTelegramAccount"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/telegram/account/heartbeat/{token}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, HeartbeatTelegramAccountOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/api/telegram/account/heartbeat/" + { + // Encode "token" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "token", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.UUIDToString(params.Token)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "forget" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "forget", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Forget.Get(); ok { + return e.EncodeValue(conv.BoolToString(val)) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeHeartbeatTelegramAccountResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// ReceiveTelegramCode invokes receiveTelegramCode operation. +// +// Receive telegram code. +// +// GET /api/telegram/code/receive/{token} +func (c *Client) ReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (*ReceiveTelegramCodeOK, error) { + res, err := c.sendReceiveTelegramCode(ctx, params) + return res, err +} + +func (c *Client) sendReceiveTelegramCode(ctx context.Context, params ReceiveTelegramCodeParams) (res *ReceiveTelegramCodeOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("receiveTelegramCode"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/api/telegram/code/receive/{token}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, ReceiveTelegramCodeOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/api/telegram/code/receive/" + { + // Encode "token" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "token", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.UUIDToString(params.Token)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeReceiveTelegramCodeResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/tgacc/oas/oas_json_gen.go b/tgacc/oas/oas_json_gen.go new file mode 100644 index 000000000..76e401dab --- /dev/null +++ b/tgacc/oas/oas_json_gen.go @@ -0,0 +1,850 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "math/bits" + "strconv" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/json" + "github.com/ogen-go/ogen/validate" +) + +// Encode implements json.Marshaler. +func (s *AcquireTelegramAccountOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *AcquireTelegramAccountOK) encodeFields(e *jx.Encoder) { + { + e.FieldStart("account_id") + s.AccountID.Encode(e) + } + { + e.FieldStart("token") + json.EncodeUUID(e, s.Token) + } +} + +var jsonFieldsNameOfAcquireTelegramAccountOK = [2]string{ + 0: "account_id", + 1: "token", +} + +// Decode decodes AcquireTelegramAccountOK from json. +func (s *AcquireTelegramAccountOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode AcquireTelegramAccountOK to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "account_id": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.AccountID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"account_id\"") + } + case "token": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := json.DecodeUUID(d) + s.Token = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"token\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode AcquireTelegramAccountOK") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountOK) { + name = jsonFieldsNameOfAcquireTelegramAccountOK[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *AcquireTelegramAccountOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *AcquireTelegramAccountOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *AcquireTelegramAccountReq) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *AcquireTelegramAccountReq) encodeFields(e *jx.Encoder) { + { + e.FieldStart("repo_owner") + e.Str(s.RepoOwner) + } + { + e.FieldStart("repo_name") + e.Str(s.RepoName) + } + { + e.FieldStart("job") + e.Str(s.Job) + } + { + e.FieldStart("run_id") + e.Int64(s.RunID) + } + { + e.FieldStart("run_attempt") + e.Int(s.RunAttempt) + } +} + +var jsonFieldsNameOfAcquireTelegramAccountReq = [5]string{ + 0: "repo_owner", + 1: "repo_name", + 2: "job", + 3: "run_id", + 4: "run_attempt", +} + +// Decode decodes AcquireTelegramAccountReq from json. +func (s *AcquireTelegramAccountReq) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode AcquireTelegramAccountReq to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "repo_owner": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.RepoOwner = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repo_owner\"") + } + case "repo_name": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.RepoName = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repo_name\"") + } + case "job": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Str() + s.Job = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"job\"") + } + case "run_id": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Int64() + s.RunID = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"run_id\"") + } + case "run_attempt": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Int() + s.RunAttempt = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"run_attempt\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode AcquireTelegramAccountReq") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00011111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfAcquireTelegramAccountReq) { + name = jsonFieldsNameOfAcquireTelegramAccountReq[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *AcquireTelegramAccountReq) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *AcquireTelegramAccountReq) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Error) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Error) encodeFields(e *jx.Encoder) { + { + e.FieldStart("error_message") + e.Str(s.ErrorMessage) + } + { + if s.TraceID.Set { + e.FieldStart("trace_id") + s.TraceID.Encode(e) + } + } + { + if s.SpanID.Set { + e.FieldStart("span_id") + s.SpanID.Encode(e) + } + } +} + +var jsonFieldsNameOfError = [3]string{ + 0: "error_message", + 1: "trace_id", + 2: "span_id", +} + +// Decode decodes Error from json. +func (s *Error) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Error to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "error_message": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.ErrorMessage = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"error_message\"") + } + case "trace_id": + if err := func() error { + s.TraceID.Reset() + if err := s.TraceID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"trace_id\"") + } + case "span_id": + if err := func() error { + s.SpanID.Reset() + if err := s.SpanID.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"span_id\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Error") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfError) { + name = jsonFieldsNameOfError[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Error) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Error) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Health) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Health) encodeFields(e *jx.Encoder) { + { + e.FieldStart("status") + e.Str(s.Status) + } + { + e.FieldStart("version") + e.Str(s.Version) + } + { + e.FieldStart("commit") + e.Str(s.Commit) + } + { + e.FieldStart("build_date") + json.EncodeDateTime(e, s.BuildDate) + } +} + +var jsonFieldsNameOfHealth = [4]string{ + 0: "status", + 1: "version", + 2: "commit", + 3: "build_date", +} + +// Decode decodes Health from json. +func (s *Health) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Health to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "status": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Status = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"status\"") + } + case "version": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Version = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"version\"") + } + case "commit": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Str() + s.Commit = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"commit\"") + } + case "build_date": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := json.DecodeDateTime(d) + s.BuildDate = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"build_date\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Health") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00001111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfHealth) { + name = jsonFieldsNameOfHealth[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Health) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Health) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes SpanID as json. +func (o OptSpanID) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes SpanID from json. +func (o *OptSpanID) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptSpanID to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptSpanID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptSpanID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes string as json. +func (o OptString) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes string from json. +func (o *OptString) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptString to nil") + } + o.Set = true + v, err := d.Str() + if err != nil { + return err + } + o.Value = string(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptString) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptString) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TraceID as json. +func (o OptTraceID) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TraceID from json. +func (o *OptTraceID) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTraceID to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTraceID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTraceID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *ReceiveTelegramCodeOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ReceiveTelegramCodeOK) encodeFields(e *jx.Encoder) { + { + if s.Code.Set { + e.FieldStart("code") + s.Code.Encode(e) + } + } +} + +var jsonFieldsNameOfReceiveTelegramCodeOK = [1]string{ + 0: "code", +} + +// Decode decodes ReceiveTelegramCodeOK from json. +func (s *ReceiveTelegramCodeOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ReceiveTelegramCodeOK to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "code": + if err := func() error { + s.Code.Reset() + if err := s.Code.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"code\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ReceiveTelegramCodeOK") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ReceiveTelegramCodeOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ReceiveTelegramCodeOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes SpanID as json. +func (s SpanID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes SpanID from json. +func (s *SpanID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode SpanID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = SpanID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s SpanID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *SpanID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TelegramAccountID as json. +func (s TelegramAccountID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes TelegramAccountID from json. +func (s *TelegramAccountID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TelegramAccountID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = TelegramAccountID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TelegramAccountID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TelegramAccountID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TraceID as json. +func (s TraceID) Encode(e *jx.Encoder) { + unwrapped := string(s) + + e.Str(unwrapped) +} + +// Decode decodes TraceID from json. +func (s *TraceID) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TraceID to nil") + } + var unwrapped string + if err := func() error { + v, err := d.Str() + unwrapped = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "alias") + } + *s = TraceID(unwrapped) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TraceID) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TraceID) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/tgacc/oas/oas_operations_gen.go b/tgacc/oas/oas_operations_gen.go new file mode 100644 index 000000000..4ee567c98 --- /dev/null +++ b/tgacc/oas/oas_operations_gen.go @@ -0,0 +1,13 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +// OperationName is the ogen operation name +type OperationName = string + +const ( + AcquireTelegramAccountOperation OperationName = "AcquireTelegramAccount" + GetHealthOperation OperationName = "GetHealth" + HeartbeatTelegramAccountOperation OperationName = "HeartbeatTelegramAccount" + ReceiveTelegramCodeOperation OperationName = "ReceiveTelegramCode" +) diff --git a/tgacc/oas/oas_parameters_gen.go b/tgacc/oas/oas_parameters_gen.go new file mode 100644 index 000000000..3a6e4ef8e --- /dev/null +++ b/tgacc/oas/oas_parameters_gen.go @@ -0,0 +1,18 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/google/uuid" +) + +// HeartbeatTelegramAccountParams is parameters of heartbeatTelegramAccount operation. +type HeartbeatTelegramAccountParams struct { + Token uuid.UUID + Forget OptBool +} + +// ReceiveTelegramCodeParams is parameters of receiveTelegramCode operation. +type ReceiveTelegramCodeParams struct { + Token uuid.UUID +} diff --git a/tgacc/oas/oas_request_encoders_gen.go b/tgacc/oas/oas_request_encoders_gen.go new file mode 100644 index 000000000..07fa2f9f6 --- /dev/null +++ b/tgacc/oas/oas_request_encoders_gen.go @@ -0,0 +1,26 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "bytes" + "net/http" + + "github.com/go-faster/jx" + + ht "github.com/ogen-go/ogen/http" +) + +func encodeAcquireTelegramAccountRequest( + req *AcquireTelegramAccountReq, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} diff --git a/tgacc/oas/oas_response_decoders_gen.go b/tgacc/oas/oas_response_decoders_gen.go new file mode 100644 index 000000000..14f8793e4 --- /dev/null +++ b/tgacc/oas/oas_response_decoders_gen.go @@ -0,0 +1,369 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func decodeAcquireTelegramAccountResponse(resp *http.Response) (res *AcquireTelegramAccountOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response AcquireTelegramAccountOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeGetHealthResponse(resp *http.Response) (res *Health, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Health + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeHeartbeatTelegramAccountResponse(resp *http.Response) (res *HeartbeatTelegramAccountOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + return &HeartbeatTelegramAccountOK{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeReceiveTelegramCodeResponse(resp *http.Response) (res *ReceiveTelegramCodeOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response ReceiveTelegramCodeOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} diff --git a/tgacc/oas/oas_schemas_gen.go b/tgacc/oas/oas_schemas_gen.go new file mode 100644 index 000000000..d686e4fd0 --- /dev/null +++ b/tgacc/oas/oas_schemas_gen.go @@ -0,0 +1,440 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "fmt" + "time" + + "github.com/google/uuid" +) + +func (s *ErrorStatusCode) Error() string { + return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) +} + +type AcquireTelegramAccountOK struct { + AccountID TelegramAccountID `json:"account_id"` + // Access token. + Token uuid.UUID `json:"token"` +} + +// GetAccountID returns the value of AccountID. +func (s *AcquireTelegramAccountOK) GetAccountID() TelegramAccountID { + return s.AccountID +} + +// GetToken returns the value of Token. +func (s *AcquireTelegramAccountOK) GetToken() uuid.UUID { + return s.Token +} + +// SetAccountID sets the value of AccountID. +func (s *AcquireTelegramAccountOK) SetAccountID(val TelegramAccountID) { + s.AccountID = val +} + +// SetToken sets the value of Token. +func (s *AcquireTelegramAccountOK) SetToken(val uuid.UUID) { + s.Token = val +} + +type AcquireTelegramAccountReq struct { + // Repository owner. + RepoOwner string `json:"repo_owner"` + // Repository name. + RepoName string `json:"repo_name"` + // Job ID. + Job string `json:"job"` + RunID int64 `json:"run_id"` + RunAttempt int `json:"run_attempt"` +} + +// GetRepoOwner returns the value of RepoOwner. +func (s *AcquireTelegramAccountReq) GetRepoOwner() string { + return s.RepoOwner +} + +// GetRepoName returns the value of RepoName. +func (s *AcquireTelegramAccountReq) GetRepoName() string { + return s.RepoName +} + +// GetJob returns the value of Job. +func (s *AcquireTelegramAccountReq) GetJob() string { + return s.Job +} + +// GetRunID returns the value of RunID. +func (s *AcquireTelegramAccountReq) GetRunID() int64 { + return s.RunID +} + +// GetRunAttempt returns the value of RunAttempt. +func (s *AcquireTelegramAccountReq) GetRunAttempt() int { + return s.RunAttempt +} + +// SetRepoOwner sets the value of RepoOwner. +func (s *AcquireTelegramAccountReq) SetRepoOwner(val string) { + s.RepoOwner = val +} + +// SetRepoName sets the value of RepoName. +func (s *AcquireTelegramAccountReq) SetRepoName(val string) { + s.RepoName = val +} + +// SetJob sets the value of Job. +func (s *AcquireTelegramAccountReq) SetJob(val string) { + s.Job = val +} + +// SetRunID sets the value of RunID. +func (s *AcquireTelegramAccountReq) SetRunID(val int64) { + s.RunID = val +} + +// SetRunAttempt sets the value of RunAttempt. +func (s *AcquireTelegramAccountReq) SetRunAttempt(val int) { + s.RunAttempt = val +} + +// Error occurred while processing request. +// Ref: #/components/schemas/Error +type Error struct { + // Human-readable error message. + ErrorMessage string `json:"error_message"` + TraceID OptTraceID `json:"trace_id"` + SpanID OptSpanID `json:"span_id"` +} + +// GetErrorMessage returns the value of ErrorMessage. +func (s *Error) GetErrorMessage() string { + return s.ErrorMessage +} + +// GetTraceID returns the value of TraceID. +func (s *Error) GetTraceID() OptTraceID { + return s.TraceID +} + +// GetSpanID returns the value of SpanID. +func (s *Error) GetSpanID() OptSpanID { + return s.SpanID +} + +// SetErrorMessage sets the value of ErrorMessage. +func (s *Error) SetErrorMessage(val string) { + s.ErrorMessage = val +} + +// SetTraceID sets the value of TraceID. +func (s *Error) SetTraceID(val OptTraceID) { + s.TraceID = val +} + +// SetSpanID sets the value of SpanID. +func (s *Error) SetSpanID(val OptSpanID) { + s.SpanID = val +} + +// ErrorStatusCode wraps Error with StatusCode. +type ErrorStatusCode struct { + StatusCode int + Response Error +} + +// GetStatusCode returns the value of StatusCode. +func (s *ErrorStatusCode) GetStatusCode() int { + return s.StatusCode +} + +// GetResponse returns the value of Response. +func (s *ErrorStatusCode) GetResponse() Error { + return s.Response +} + +// SetStatusCode sets the value of StatusCode. +func (s *ErrorStatusCode) SetStatusCode(val int) { + s.StatusCode = val +} + +// SetResponse sets the value of Response. +func (s *ErrorStatusCode) SetResponse(val Error) { + s.Response = val +} + +// Ref: #/components/schemas/Health +type Health struct { + // Health status. + Status string `json:"status"` + // Service version. + Version string `json:"version"` + // Service commit. + Commit string `json:"commit"` + // Service build date. + BuildDate time.Time `json:"build_date"` +} + +// GetStatus returns the value of Status. +func (s *Health) GetStatus() string { + return s.Status +} + +// GetVersion returns the value of Version. +func (s *Health) GetVersion() string { + return s.Version +} + +// GetCommit returns the value of Commit. +func (s *Health) GetCommit() string { + return s.Commit +} + +// GetBuildDate returns the value of BuildDate. +func (s *Health) GetBuildDate() time.Time { + return s.BuildDate +} + +// SetStatus sets the value of Status. +func (s *Health) SetStatus(val string) { + s.Status = val +} + +// SetVersion sets the value of Version. +func (s *Health) SetVersion(val string) { + s.Version = val +} + +// SetCommit sets the value of Commit. +func (s *Health) SetCommit(val string) { + s.Commit = val +} + +// SetBuildDate sets the value of BuildDate. +func (s *Health) SetBuildDate(val time.Time) { + s.BuildDate = val +} + +// HeartbeatTelegramAccountOK is response for HeartbeatTelegramAccount operation. +type HeartbeatTelegramAccountOK struct{} + +// NewOptBool returns new OptBool with value set to v. +func NewOptBool(v bool) OptBool { + return OptBool{ + Value: v, + Set: true, + } +} + +// OptBool is optional bool. +type OptBool struct { + Value bool + Set bool +} + +// IsSet returns true if OptBool was set. +func (o OptBool) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBool) Reset() { + var v bool + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBool) SetTo(v bool) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBool) Get() (v bool, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBool) Or(d bool) bool { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptSpanID returns new OptSpanID with value set to v. +func NewOptSpanID(v SpanID) OptSpanID { + return OptSpanID{ + Value: v, + Set: true, + } +} + +// OptSpanID is optional SpanID. +type OptSpanID struct { + Value SpanID + Set bool +} + +// IsSet returns true if OptSpanID was set. +func (o OptSpanID) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptSpanID) Reset() { + var v SpanID + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptSpanID) SetTo(v SpanID) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptSpanID) Get() (v SpanID, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptSpanID) Or(d SpanID) SpanID { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptString returns new OptString with value set to v. +func NewOptString(v string) OptString { + return OptString{ + Value: v, + Set: true, + } +} + +// OptString is optional string. +type OptString struct { + Value string + Set bool +} + +// IsSet returns true if OptString was set. +func (o OptString) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptString) Reset() { + var v string + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptString) SetTo(v string) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptString) Get() (v string, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptString) Or(d string) string { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTraceID returns new OptTraceID with value set to v. +func NewOptTraceID(v TraceID) OptTraceID { + return OptTraceID{ + Value: v, + Set: true, + } +} + +// OptTraceID is optional TraceID. +type OptTraceID struct { + Value TraceID + Set bool +} + +// IsSet returns true if OptTraceID was set. +func (o OptTraceID) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTraceID) Reset() { + var v TraceID + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTraceID) SetTo(v TraceID) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTraceID) Get() (v TraceID, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTraceID) Or(d TraceID) TraceID { + if v, ok := o.Get(); ok { + return v + } + return d +} + +type ReceiveTelegramCodeOK struct { + // Code. + Code OptString `json:"code"` +} + +// GetCode returns the value of Code. +func (s *ReceiveTelegramCodeOK) GetCode() OptString { + return s.Code +} + +// SetCode sets the value of Code. +func (s *ReceiveTelegramCodeOK) SetCode(val OptString) { + s.Code = val +} + +type SpanID string + +type TelegramAccountID string + +type TokenAuth struct { + APIKey string +} + +// GetAPIKey returns the value of APIKey. +func (s *TokenAuth) GetAPIKey() string { + return s.APIKey +} + +// SetAPIKey sets the value of APIKey. +func (s *TokenAuth) SetAPIKey(val string) { + s.APIKey = val +} + +type TraceID string diff --git a/tgacc/oas/oas_security_gen.go b/tgacc/oas/oas_security_gen.go new file mode 100644 index 000000000..c7f571d7d --- /dev/null +++ b/tgacc/oas/oas_security_gen.go @@ -0,0 +1,25 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + "net/http" + + "github.com/go-faster/errors" +) + +// SecuritySource is provider of security values (tokens, passwords, etc.). +type SecuritySource interface { + // TokenAuth provides tokenAuth security value. + TokenAuth(ctx context.Context, operationName OperationName) (TokenAuth, error) +} + +func (s *Client) securityTokenAuth(ctx context.Context, operationName OperationName, req *http.Request) error { + t, err := s.sec.TokenAuth(ctx, operationName) + if err != nil { + return errors.Wrap(err, "security source \"TokenAuth\"") + } + req.Header.Set("Token", t.APIKey) + return nil +} diff --git a/tgacc/oas/oas_validators_gen.go b/tgacc/oas/oas_validators_gen.go new file mode 100644 index 000000000..d544b2fda --- /dev/null +++ b/tgacc/oas/oas_validators_gen.go @@ -0,0 +1,189 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/validate" +) + +func (s *AcquireTelegramAccountOK) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.AccountID.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "account_id", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *Error) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.TraceID.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "trace_id", + Error: err, + }) + } + if err := func() error { + if value, ok := s.SpanID.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "span_id", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *ErrorStatusCode) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.Response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "Response", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *ReceiveTelegramCodeOK) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.Code.Get(); ok { + if err := func() error { + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["^[0-9]{3,6}$"], + }).Validate(string(value)); err != nil { + return errors.Wrap(err, "string") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "code", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s SpanID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["[[:xdigit:]]{16}"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} + +func (s TelegramAccountID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["^[0-9]{7,15}$"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} + +func (s TraceID) Validate() error { + alias := (string)(s) + if err := (validate.String{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 0, + MaxLengthSet: false, + Email: false, + Hostname: false, + Regex: regexMap["[[:xdigit:]]{32}"], + }).Validate(string(alias)); err != nil { + return errors.Wrap(err, "string") + } + return nil +} From 0909430bf333ab0007eff7aa7048ca251e1fda8c Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:54:26 +0300 Subject: [PATCH 06/11] test: fix after refactorings --- telegram/internal/e2etest/suite.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telegram/internal/e2etest/suite.go b/telegram/internal/e2etest/suite.go index 1143ac9d4..ae2487d12 100644 --- a/telegram/internal/e2etest/suite.go +++ b/telegram/internal/e2etest/suite.go @@ -54,6 +54,8 @@ func NewSuite(t *testing.T, config TestOptions) *Suite { dc: config.DC, logger: config.Logger, manager: manager, + rand: config.Random, + used: make(map[string]struct{}), } if managerEnabled, _ := strconv.ParseBool(os.Getenv("TEST_ACCOUNTS_BROKEN")); managerEnabled { t.Log("External test accounts are used as per TEST_ACCOUNTS_BROKEN") From 2cb1a0ae57816c52f506573c3912a4e9b3c96b7b Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:55:42 +0300 Subject: [PATCH 07/11] test: closers --- telegram/internal/e2etest/auth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram/internal/e2etest/auth.go b/telegram/internal/e2etest/auth.go index e2628892a..19fd06099 100644 --- a/telegram/internal/e2etest/auth.go +++ b/telegram/internal/e2etest/auth.go @@ -16,6 +16,7 @@ func (s *Suite) createFlow(ctx context.Context) (auth.Flow, error) { if err != nil { return auth.Flow{}, errors.Wrap(err, "acquire account") } + s.closers = append(s.closers, account.Close) return auth.NewFlow(account.UserAuthenticator, auth.SendCodeOptions{}), nil } From 76854ea79045970780d800dc6549c4e5ec65576b Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 20:56:16 +0300 Subject: [PATCH 08/11] test: remove unused env var --- telegram/client_external_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/telegram/client_external_test.go b/telegram/client_external_test.go index 4d30600d6..0f084d87e 100644 --- a/telegram/client_external_test.go +++ b/telegram/client_external_test.go @@ -2,8 +2,6 @@ package telegram_test import ( "context" - "os" - "strconv" "strings" "testing" "time" @@ -81,10 +79,6 @@ const dialog = `— Да? func TestExternalE2EUsersDialog(t *testing.T) { testutil.SkipExternal(t) - if v, _ := strconv.ParseBool(os.Getenv("GOTD_E2E_DIALOGS_BROKEN")); v { - // TODO(ernado): enable when fixed - t.Skip("Dialogs are broken.") - } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() From 2647a7772b081d06d4207b7321ed6a01a4f1ac46 Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 21:32:13 +0300 Subject: [PATCH 09/11] test: pass token to authenticator --- tgacc/tgacc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tgacc/tgacc.go b/tgacc/tgacc.go index 01532f2b8..d84aeeb66 100644 --- a/tgacc/tgacc.go +++ b/tgacc/tgacc.go @@ -48,6 +48,7 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) UserAuthenticator: &codeAuth{ phone: phone, client: t.client, + token: res.Token, }, token: res.Token, From 943ef6248d656e30bd24eecbd5cc3891931beaad Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 21:34:23 +0300 Subject: [PATCH 10/11] test(tgacc): heartbeats --- tgacc/tgacc.go | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tgacc/tgacc.go b/tgacc/tgacc.go index d84aeeb66..549940497 100644 --- a/tgacc/tgacc.go +++ b/tgacc/tgacc.go @@ -43,7 +43,7 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) phone := string(res.AccountID) - return &TestAccount{ + ta := &TestAccount{ Phone: phone, UserAuthenticator: &codeAuth{ phone: phone, @@ -53,7 +53,9 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) token: res.Token, client: t.client, - }, nil + } + go ta.heartBeats() + return ta, nil } type ghSecuritySource struct{} @@ -68,12 +70,36 @@ type TestAccount struct { Phone string UserAuthenticator auth.UserAuthenticator - token uuid.UUID - client *oas.Client + token uuid.UUID + client *oas.Client + heartbeat chan struct{} +} + +func (t TestAccount) heartBeats() { + ticker := time.NewTicker(time.Second * 10) + defer ticker.Stop() + + for { + select { + case <-t.heartbeat: + return + case <-ticker.C: + t.sendHeartBeat() + } + } +} + +func (t TestAccount) sendHeartBeat() { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + _ = t.client.HeartbeatTelegramAccount(ctx, oas.HeartbeatTelegramAccountParams{ + Token: t.token, + }) } // Close releases telegram account. func (t TestAccount) Close() error { + close(t.heartbeat) ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() return t.client.HeartbeatTelegramAccount(ctx, oas.HeartbeatTelegramAccountParams{ From 11f521667c4c9e9687f32b0d749dd31be9e21adb Mon Sep 17 00:00:00 2001 From: Aleksandr Razumov Date: Mon, 9 Dec 2024 21:40:41 +0300 Subject: [PATCH 11/11] test(tgacc): make channel non-nil --- tgacc/tgacc.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tgacc/tgacc.go b/tgacc/tgacc.go index 549940497..191ceed50 100644 --- a/tgacc/tgacc.go +++ b/tgacc/tgacc.go @@ -51,8 +51,9 @@ func (t *TestAccountManager) Acquire(ctx context.Context) (*TestAccount, error) token: res.Token, }, - token: res.Token, - client: t.client, + token: res.Token, + client: t.client, + heartbeat: make(chan struct{}), } go ta.heartBeats() return ta, nil