mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-02 12:42:13 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4fe657bd9 | ||
|
|
31473fbe10 | ||
|
|
618235bd72 | ||
|
|
49e1e56aa1 | ||
|
|
ad6a4ef9b2 | ||
|
|
46602a229c | ||
|
|
b0290dc33d | ||
|
|
914810fd13 | ||
|
|
2c6ed03823 | ||
|
|
6a97079454 | ||
|
|
1c879148d8 | ||
|
|
0347212b64 | ||
|
|
f68f55c7e9 | ||
|
|
a5bb5e04da | ||
|
|
7f1f826468 | ||
|
|
47b9db0215 | ||
|
|
ba8d261591 | ||
|
|
5f1d2a9745 | ||
|
|
b27ba8e984 |
@@ -36,7 +36,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
with:
|
||||
buildkitd-flags: "--debug"
|
||||
-
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
with:
|
||||
buildkitd-flags: "--debug"
|
||||
-
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@18ce135bb5112fa8ce4ed6c17ab05699d7f3a5e0 # v1
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v1
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
@@ -69,8 +69,8 @@ require (
|
||||
github.com/posener/complete v1.2.3
|
||||
github.com/pquerna/cachecontrol v0.2.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.64.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
@@ -101,15 +101,15 @@ require (
|
||||
gocloud.dev/pubsub/natspubsub v0.41.0
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.41.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
|
||||
golang.org/x/image v0.27.0
|
||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476
|
||||
golang.org/x/image v0.28.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/tools v0.34.0
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
google.golang.org/api v0.234.0
|
||||
google.golang.org/api v0.238.0
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/grpc v1.73.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
@@ -125,9 +125,9 @@ require (
|
||||
github.com/Jille/raft-grpc-transport v1.6.1
|
||||
github.com/arangodb/go-driver v1.6.6
|
||||
github.com/armon/go-metrics v0.4.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1
|
||||
github.com/cognusion/imaging v1.0.2
|
||||
github.com/fluent/fluent-logger-golang v1.10.0
|
||||
@@ -137,12 +137,12 @@ require (
|
||||
github.com/hanwen/go-fuse/v2 v2.8.0
|
||||
github.com/hashicorp/raft v1.7.3
|
||||
github.com/hashicorp/raft-boltdb/v2 v2.3.1
|
||||
github.com/minio/crc64nvme v1.0.1
|
||||
github.com/minio/crc64nvme v1.0.2
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1
|
||||
github.com/parquet-go/parquet-go v0.24.0
|
||||
github.com/pkg/sftp v1.13.7
|
||||
github.com/parquet-go/parquet-go v0.25.1
|
||||
github.com/pkg/sftp v1.13.9
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/rclone/rclone v1.69.3
|
||||
github.com/rclone/rclone v1.70.1
|
||||
github.com/rdleal/intervalst v1.5.0
|
||||
github.com/redis/go-redis/v9 v9.10.0
|
||||
github.com/schollz/progressbar/v3 v3.18.0
|
||||
@@ -159,92 +159,99 @@ require (
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.23.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.97 // indirect
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.173 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
|
||||
github.com/IBM/go-sdk-core/v5 v5.20.0 // indirect
|
||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect
|
||||
github.com/ProtonMail/go-srp v0.0.7 // indirect
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.8.1 // indirect
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.9.0 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||
github.com/abbot/go-http-auth v0.4.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc // indirect
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.77 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.34.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/boltdb/bolt v1.3.1 // indirect
|
||||
github.com/bradenaw/juniper v0.15.2 // indirect
|
||||
github.com/bradenaw/juniper v0.15.3 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/buengese/sgzip v0.1.1 // indirect
|
||||
github.com/calebcase/tmpfile v1.0.3 // indirect
|
||||
github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.9.0 // indirect
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6 // indirect
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.10.0 // indirect
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc // indirect
|
||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
|
||||
github.com/colinmarc/hdfs/v2 v2.4.0 // indirect
|
||||
github.com/creasty/defaults v1.7.0 // indirect
|
||||
github.com/creasty/defaults v1.8.0 // indirect
|
||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
|
||||
github.com/d4l3k/messagediff v1.2.1 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
|
||||
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/emersion/go-message v0.18.0 // indirect
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
|
||||
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 // indirect
|
||||
github.com/emersion/go-message v0.18.2 // indirect
|
||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/flynn/noise v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
github.com/flynn/noise v1.1.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/geoffgarside/ber v1.2.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.2 // indirect
|
||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
@@ -270,33 +277,35 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7 // indirect
|
||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 // indirect
|
||||
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lanrat/extsort v1.0.2 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lpar/date v1.0.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/nats.go v1.40.1 // indirect
|
||||
github.com/nats-io/nkeys v0.4.10 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/ncw/swift/v2 v2.0.3 // indirect
|
||||
github.com/ncw/swift/v2 v2.0.4 // indirect
|
||||
github.com/nxadm/tail v1.4.11 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/onsi/gomega v1.34.1 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.23.3 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.80.0 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.9.1 // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.93.0 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.11.3 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 // indirect
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
@@ -307,31 +316,31 @@ require (
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/xattr v0.4.10 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 // indirect
|
||||
github.com/relvacode/iso8601 v1.3.0 // indirect
|
||||
github.com/relvacode/iso8601 v1.6.0 // indirect
|
||||
github.com/rfjakob/eme v1.1.2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/samber/lo v1.47.0 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.24.12 // indirect
|
||||
github.com/samber/lo v1.50.0 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/smartystreets/goconvey v1.8.1 // indirect
|
||||
github.com/sony/gobreaker v0.5.0 // indirect
|
||||
github.com/sony/gobreaker v1.0.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.22 // indirect
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.24 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002 // indirect
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5 // indirect
|
||||
github.com/tarantool/go-iproto v1.1.0 // indirect
|
||||
github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a // indirect
|
||||
github.com/tikv/pd/client v0.0.0-20230329114254-1948c247c2b1 // indirect
|
||||
github.com/tinylib/msgp v1.3.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/twmb/murmur3 v1.1.3 // indirect
|
||||
github.com/unknwon/goconfig v1.0.0 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
@@ -343,36 +352,37 @@ require (
|
||||
github.com/ydb-platform/ydb-go-yc-metadata v0.6.1 // indirect
|
||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.etcd.io/bbolt v1.3.10 // indirect
|
||||
go.etcd.io/bbolt v1.4.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.1 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/validator.v2 v2.0.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.65.10 // indirect
|
||||
moul.io/http2curl/v2 v2.3.0 // indirect
|
||||
storj.io/common v0.0.0-20240812101423-26b53789c348 // indirect
|
||||
storj.io/drpc v0.0.35-0.20240709171858-0075ac871661 // indirect
|
||||
storj.io/eventkit v0.0.0-20240415002644-1d9596fee086 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
storj.io/common v0.0.0-20250605163628-70ca83b6228e // indirect
|
||||
storj.io/drpc v0.0.35-0.20250513201419-f7819ea69b55 // indirect
|
||||
storj.io/eventkit v0.0.0-20250410172343-61f26d3de156 // indirect
|
||||
storj.io/infectious v0.0.2 // indirect
|
||||
storj.io/picobuf v0.0.3 // indirect
|
||||
storj.io/picobuf v0.0.4 // indirect
|
||||
storj.io/uplink v1.13.1 // indirect
|
||||
)
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo
|
||||
cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
|
||||
cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
|
||||
cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
|
||||
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
|
||||
@@ -541,20 +541,20 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum
|
||||
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
|
||||
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 h1:j8BorDEigD8UFOSZQiSqAMOOleyQOOQPnUAwV+Ls1gA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0 h1:mJVYrRyo7/ISs3MLMHphqssqbS1vLJ3uiwo1+fY8OUQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.4.0/go.mod h1:QXy84HaR0FHLPWaGQDBrZZbdCPTshwGl3gQ64uR/Zrc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 h1:LR0kAX9ykz8G4YgLCaRDVJ3+n43R8MneB5dTy2konZo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1 h1:iXgRWOnlPG3AZwBYInDOOJ3PVe3mrL2EPkCY4KfGxKw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1/go.mod h1:WtRlkDNMdVDrsTyLXNHkVrzkvfbdZXgoCu4PZbq9rgg=
|
||||
github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk=
|
||||
github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
@@ -578,8 +578,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.97 h1:c+mQoiES/21JrHDAxJLCYICJO+bu8Clv0ZDNZe7Ndyk=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.97/go.mod h1:Y/bCHoPJNPKz2hw1ADXjQXJP378HODwK+g/5SR2gqfU=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.173 h1:OPDjpkEWXO+WSGX1qQ10Y51do178i9z4DdFpI25B+iY=
|
||||
github.com/Files-com/files-sdk-go/v3 v3.2.173/go.mod h1:HnPrW1lljxOjdkR5Wm6DjtdHwWdcm/afts2N6O+iiJo=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU=
|
||||
@@ -588,6 +588,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
|
||||
github.com/IBM/go-sdk-core/v5 v5.20.0 h1:rG1fn5GmJfFzVtpDKndsk6MgcarluG8YIWf89rVqLP8=
|
||||
github.com/IBM/go-sdk-core/v5 v5.20.0/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
|
||||
github.com/Jille/raft-grpc-transport v1.6.1 h1:gN3sjapb+fVbiebS7AfQQgbV2ecTOI7ur7NPPC7Mhoc=
|
||||
github.com/Jille/raft-grpc-transport v1.6.1/go.mod h1:HbOjEdu/yzCJ/mjTF6wEOJNbAUpHfU2UOA2hVD4CNFg=
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
|
||||
@@ -605,17 +607,16 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e h1:lCsqUUACrcMC83lg5rTo9Y0PnPItE61JSfvMyIcANwk=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
||||
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
||||
github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=
|
||||
github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4 h1:Vz/8+HViFFnf2A6XX8JOvZMrA6F5puwNvvF21O1mRlo=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g=
|
||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=
|
||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4=
|
||||
github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A=
|
||||
github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g=
|
||||
@@ -637,9 +638,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
|
||||
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
|
||||
@@ -651,34 +651,36 @@ github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho=
|
||||
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
|
||||
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4 h1:GySzjhVvx0ERP6eyfAbAuAXLtAda5TEy19E5q5W8I9E=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.4/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69 h1:8B8ZQboRc3uaIKjshve/XlvJ570R7BKNy3gftSbS178=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.69/go.mod h1:gPME6I8grR1jCqBFEGthULiolzf/Sexq/Wy42ibKK9c=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31 h1:oQWSGexYasNpYp4epLGZxxjsDo8BMBh6iNWkTXQvkwk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.31/go.mod h1:nc332eGUU+djP3vrMI6blS0woaCfHTe3KiSQUVTMRq0=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35 h1:o1v1VFfPcDVlK3ll1L5xHsaQAFdNtZ5GXnNR7SwueC4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.35/go.mod h1:rZUQNYMNG+8uZxz9FOerQJ+FceCiodXvixpeRtdESrU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35 h1:R5b82ubO2NntENm3SAm0ADME+H630HomNJdgv+yZ3xw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.35/go.mod h1:FuA+nmgMRfkzVKYDNEqQadvEMxtxl9+RLT9ribCwEMs=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.77 h1:xaRN9fags7iJznsMEjtcEuON1hGfCZ0y5MVfEMKtrx8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.77/go.mod h1:lolsiGkT47AZ3DWqtxgEQM/wVMpayi7YWNjl3wHSRx8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 h1:BCG7DCXEXpNCcpwCxg1oi9pkJWH2+eZzTn9MY56MbVw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16 h1:/ldKrPPXTC421bTNWrUIpq3CxwHwRI/kpc+jPUTJocM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.16/go.mod h1:5vkf/Ws0/wgIMJDQbjI4p2op86hNW6Hie5QtebrDgT8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.80.1 h1:xYEAf/6QHiTZDccKnPMbsMwlau13GsDsTgdue3wmHGw=
|
||||
@@ -687,14 +689,14 @@ github.com/aws/aws-sdk-go-v2/service/sns v1.34.2 h1:PajtbJ/5bEo6iUAIGMYnK8ljqg2F
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.34.2/go.mod h1:PJtxxMdj747j8DeZENRTTYAz/lx/pADn/U0k7YNNiUY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.3 h1:j5BchjfDoS7K26vPdyJlyxBIIBGDflq3qjjJKBDlbcI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.3/go.mod h1:Bar4MrRxeqdn6XIh8JGfiXuFRmyrrsZNTJotxEJmWW0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4 h1:EU58LP8ozQDVroOEyAfcq0cGc5R/FTZjVoYJ6tvby3w=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.4/go.mod h1:CrtOgCcysxMvrCoHnvNAD7PHWclmoFG78Q2xLK0KKcs=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2 h1:XB4z0hbQtpmBnb1FQYvKaCM7UsS6Y/u8jVBwIUGeCTk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.2/go.mod h1:hwRpqkRxnQ58J9blRDrB4IanlXCpcKmsC83EhG77upg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21 h1:nyLjs8sYJShFYj6aiyjCBI3EcLn1udWrQTjEF+SOXB0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21/go.mod h1:EhdxtZ+g84MSGrSrHzZiUm9PYiZkrADNja15wtRJSJo=
|
||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
|
||||
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
|
||||
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@@ -708,8 +710,8 @@ github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/bradenaw/juniper v0.15.2 h1:0JdjBGEF2jP1pOxmlNIrPhAoQN7Ng5IMAY5D0PHMW4U=
|
||||
github.com/bradenaw/juniper v0.15.2/go.mod h1:UX4FX57kVSaDp4TPqvSjkAAewmRFAfXf27BOs5z9dq8=
|
||||
github.com/bradenaw/juniper v0.15.3 h1:RHIAMEDTpvmzV1wg1jMAHGOoI2oJUSPx3lxRldXnFGo=
|
||||
github.com/bradenaw/juniper v0.15.3/go.mod h1:UX4FX57kVSaDp4TPqvSjkAAewmRFAfXf27BOs5z9dq8=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
@@ -719,13 +721,12 @@ github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0
|
||||
github.com/buengese/sgzip v0.1.1 h1:ry+T8l1mlmiWEsDrH/YHZnCVWD2S3im1KLsyO+8ZmTU=
|
||||
github.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzOS8VMas=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo=
|
||||
github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
@@ -749,17 +750,16 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.9.0 h1:8C76QklmuV4qmKAC7cUnu9D68X9kCkFMuLspPikECCo=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.9.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6 h1:mLY/79N73URZ2J/oRKTxmfhCgxThzBmjQ6XOjX5tYjI=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20241223203758-52b943b88fd6/go.mod h1:0aLYPsmguHbok591y6hI5yAqU0drbUzrPEO10ZpgTTw=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.10.0 h1:Gi4p2KmmA6E9M7MI43PFw/hd4svnkHmR0ElfMcpLkHE=
|
||||
github.com/cloudinary/cloudinary-go/v2 v2.10.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc h1:t8YjNUCt1DimB4HCIXBztwWMhgxr5yG5/YaRl9Afdfg=
|
||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc/go.mod h1:CgWpFCFWzzEA5hVkhAc6DZZzGd3czx+BblvOzjmg6KA=
|
||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc h1:0xCWmFKBmarCqqqLeM7jFBSw/Or81UEElFqO8MY+GDs=
|
||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc/go.mod h1:uvR42Hb/t52HQd7x5/ZLzZEK8oihrFpgnodIJ1vte2E=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -784,8 +784,8 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA=
|
||||
github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
||||
github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=
|
||||
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
||||
github.com/cronokirby/saferith v0.33.0 h1:TgoQlfsD4LIwx71+ChfRcIpjkw+RPOapDEVxa+LhwLo=
|
||||
github.com/cronokirby/saferith v0.33.0/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA=
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
|
||||
@@ -819,16 +819,14 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
|
||||
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/emersion/go-message v0.18.0 h1:7LxAXHRpSeoO/Wom3ZApVZYG7c3d17yCScYce8WiXA8=
|
||||
github.com/emersion/go-message v0.18.0/go.mod h1:Zi69ACvzaoV/MBnrxfVBPV3xWEuCmC2nEN39oJF4B8A=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA=
|
||||
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
||||
github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7x/Lpg=
|
||||
github.com/emersion/go-message v0.18.2/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
|
||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff h1:4N8wnS3f1hNHSmFD5zgFkWCyA4L1kCDkImPAtK7D6tg=
|
||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@@ -869,8 +867,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fluent/fluent-logger-golang v1.10.0 h1:JcLj8u3WclQv2juHGKTSzBRM5vIZjEqbrmvn/n+m1W0=
|
||||
github.com/fluent/fluent-logger-golang v1.10.0/go.mod h1:UNyv8FAGmQcYJRtk+yfxhWqWUwsabTipgjXvBDR8kTs=
|
||||
github.com/flynn/noise v1.0.1 h1:vPp/jdQLXC6ppsXSj/pM3W1BIJ5FEHE2TulSJBpb43Y=
|
||||
github.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
@@ -883,15 +881,15 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
|
||||
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
|
||||
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/geoffgarside/ber v1.2.0 h1:/loowoRcs/MWLYmGX9QtIAbA+V/FrnVLsMMPhwiRm64=
|
||||
github.com/geoffgarside/ber v1.2.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
||||
github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg=
|
||||
github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||
@@ -919,21 +917,27 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-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/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/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-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-openapi/errors v0.22.1 h1:kslMRRnK7NCb/CvR1q1VWuEQCEIsBGn5GgKD9e+HYhU=
|
||||
github.com/go-openapi/errors v0.22.1/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
|
||||
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
||||
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
||||
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
|
||||
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
|
||||
@@ -942,8 +946,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA=
|
||||
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
|
||||
github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
|
||||
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -956,13 +960,14 @@ github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL
|
||||
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
|
||||
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus=
|
||||
github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
@@ -1227,8 +1232,8 @@ github.com/karlseguin/ccache/v2 v2.0.8/go.mod h1:2BDThcfQMf/c0jnZowt16eW405XIqZP
|
||||
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLMY72r5J4sEfkuE7AFbixEP2qRbEcum/wA=
|
||||
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
|
||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
|
||||
@@ -1236,9 +1241,8 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA=
|
||||
github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -1263,6 +1267,8 @@ github.com/kurin/blazer v0.5.3 h1:SAgYv0TKU0kN/ETfO5ExjNAPyMt2FocO2s/UlCHfjAk=
|
||||
github.com/kurin/blazer v0.5.3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lanrat/extsort v1.0.2 h1:p3MLVpQEPwEGPzeLBb+1eSErzRl6Bgjgr+qnIs2RxrU=
|
||||
github.com/lanrat/extsort v1.0.2/go.mod h1:ivzsdLm8Tv+88qbdpMElV6Z15StlzPUtZSKsGb51hnQ=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
@@ -1271,8 +1277,8 @@ github.com/linxGnu/grocksdb v1.10.1 h1:YX6gUcKvSC3d0s9DaqgbU+CRkZHzlELgHu1Z/kmts
|
||||
github.com/linxGnu/grocksdb v1.10.1/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk=
|
||||
github.com/lpar/date v1.0.0 h1:bq/zVqFTUmsxvd/CylidY4Udqpr9BOFrParoP6p0x/I=
|
||||
github.com/lpar/date v1.0.0/go.mod h1:KjYe0dDyMQTgpqcUz4LEIeM5VZwhggjVx/V2dtc8NSo=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
||||
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
|
||||
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
|
||||
@@ -1280,8 +1286,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||
github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo=
|
||||
github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0=
|
||||
@@ -1291,21 +1297,22 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
|
||||
github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
|
||||
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
|
||||
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -1333,40 +1340,40 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
||||
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
||||
github.com/ncw/swift/v2 v2.0.4 h1:hHWVFxn5/YaTWAASmn4qyq2p6OyP/Hm3vMLzkjEqR7w=
|
||||
github.com/ncw/swift/v2 v2.0.4/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
||||
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
||||
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
|
||||
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.80.0 h1:Rr7QLMozd2DfDBKo6AB3DzLYQxAwuOG118+K5AAD5E8=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.80.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.93.0 h1:L6cfEXHZYW9WXD+q0g+HPvLS5TkZjpn3b0RlkLWOLpM=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.93.0/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
|
||||
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
|
||||
github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw=
|
||||
github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
|
||||
github.com/parquet-go/parquet-go v0.24.0 h1:VrsifmLPDnas8zpoHmYiWDZ1YHzLmc7NmNwPGkI2JM4=
|
||||
github.com/parquet-go/parquet-go v0.24.0/go.mod h1:OqBBRGBl7+llplCvDMql8dEKaDqjaFA/VAPw+OJiNiw=
|
||||
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
||||
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
||||
github.com/parquet-go/parquet-go v0.25.1 h1:l7jJwNM0xrk0cnIIptWMtnSnuxRkwq53S+Po3KG8Xgo=
|
||||
github.com/parquet-go/parquet-go v0.25.1/go.mod h1:AXBuotO1XiBtcqJb/FKFyjBG4aqa3aQAAWF3ZPzCanY=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU=
|
||||
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
|
||||
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
|
||||
@@ -1402,8 +1409,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM=
|
||||
github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
@@ -1413,8 +1420,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k=
|
||||
github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
|
||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
||||
@@ -1430,14 +1437,14 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
|
||||
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
@@ -1447,14 +1454,12 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8=
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
|
||||
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/rclone/rclone v1.69.3 h1:UbNEc7pVYDYhoMzlj9+NG/vYjDKI4SSQgZCsWeSYZng=
|
||||
github.com/rclone/rclone v1.69.3/go.mod h1:5ryHJK+Y28R7SXpYOWv0mP85Fh4kSh2fZWLN5oPuc8Q=
|
||||
github.com/rclone/rclone v1.70.1 h1:Agc6eFbA0taLiogGN/G+O1GjFOK73hcUOxs6EEOd6ME=
|
||||
github.com/rclone/rclone v1.70.1/go.mod h1:YrYCOkNPFbOp+ORFu9/M1afuu71QS/rSjFafv5BxqUI=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rdleal/intervalst v1.5.0 h1:SEB9bCFz5IqD1yhfH1Wv8IBnY/JQxDplwkxHjT6hamU=
|
||||
@@ -1466,8 +1471,8 @@ github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD1
|
||||
github.com/rekby/fixenv v0.3.2/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
|
||||
github.com/rekby/fixenv v0.6.1 h1:jUFiSPpajT4WY2cYuc++7Y1zWrnCxnovGCIX72PZniM=
|
||||
github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c=
|
||||
github.com/relvacode/iso8601 v1.3.0 h1:HguUjsGpIMh/zsTczGN3DVJFxTU/GX+MMmzcKoMO7ko=
|
||||
github.com/relvacode/iso8601 v1.3.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=
|
||||
github.com/relvacode/iso8601 v1.6.0 h1:eFXUhMJN3Gz8Rcq82f9DTMW0svjtAVuIEULglM7QHTU=
|
||||
github.com/relvacode/iso8601 v1.6.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
@@ -1480,16 +1485,16 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
|
||||
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
|
||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
|
||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||
github.com/seaweedfs/goexif v1.0.3 h1:ve/OjI7dxPW8X9YQsv3JuVMaxEyF9Rvfd04ouL+Bz30=
|
||||
@@ -1500,8 +1505,8 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
|
||||
github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@@ -1521,12 +1526,13 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS
|
||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/snabb/httpreaderat v1.0.1 h1:whlb+vuZmyjqVop8x1EKOg05l2NE4z9lsMMXjmSUCnY=
|
||||
github.com/snabb/httpreaderat v1.0.1/go.mod h1:lpbGrKDWF37yvRbtRvQsbesS6Ty5c83t8ztannPoMsA=
|
||||
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
|
||||
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ=
|
||||
github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.22 h1:4/g8IVItBDKLdVnqrdHZrCVPpIrwDBzl1jrV0IHQHDU=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.22/go.mod h1:XkZYGzknZwkD0AKUnZaSXhRiVTLCkq7CWVa3IsE72gA=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.24 h1:cKixJ+evHnfJhWNyIZjBy5hoW8LTWmrJXPo18tzLNrk=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.24/go.mod h1:XkZYGzknZwkD0AKUnZaSXhRiVTLCkq7CWVa3IsE72gA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
@@ -1569,8 +1575,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002 h1:jevGbwKzMmHLgHAaDaMJLQX3jpXUWjUvnsrPeMgkM7o=
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213150454-ec0027fb0002/go.mod h1:0Mv/XWQoRWF7d7jkc4DufsAJQg8xyZ5NtCkY59wECQY=
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5 h1:Sa+sR8aaAMFwxhXWENEnE6ZpqhZ9d7u1RT2722Rw6hc=
|
||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5/go.mod h1:UdZiFUFu6e2WjjtjxivwXWcwc1N/8zgbkBR9QNucUOY=
|
||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||
github.com/tarantool/go-iproto v1.1.0 h1:HULVOIHsiehI+FnHfM7wMDntuzUddO09DKqu2WnFQ5A=
|
||||
github.com/tarantool/go-iproto v1.1.0/go.mod h1:LNCtdyZxojUed8SbOiYHoc3v9NvaZTB7p96hUySMlIo=
|
||||
@@ -1591,10 +1597,10 @@ github.com/tikv/pd/client v0.0.0-20230329114254-1948c247c2b1/go.mod h1:3cTcfo8GR
|
||||
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
||||
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
||||
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/tsuna/gohbase v0.0.0-20201125011725-348991136365 h1:6iRwZdrFUzbcVYZwa8dXTIILGIxmmhjyUPJEcwzPGaU=
|
||||
github.com/tsuna/gohbase v0.0.0-20201125011725-348991136365/go.mod h1:zj0GJHGvyf1ed3Jm/Tb4830c/ZKDq+YoLsCt2rGQuT0=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
@@ -1659,12 +1665,11 @@ github.com/yunify/qingstor-sdk-go/v3 v3.2.0 h1:9sB2WZMgjwSUNZhrgvaNGazVltoFUUfuS
|
||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/assert v1.3.1 h1:vukIABvugfNMZMQO1ABsyQDJDTVQbn+LWSMy1ol1h6A=
|
||||
github.com/zeebo/assert v1.3.1/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
|
||||
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
@@ -1672,8 +1677,8 @@ github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l
|
||||
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||
go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ=
|
||||
go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.etcd.io/etcd/api/v3 v3.6.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo=
|
||||
go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk=
|
||||
@@ -1695,22 +1700,22 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
@@ -1724,8 +1729,8 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
@@ -1741,8 +1746,8 @@ gocloud.dev/pubsub/natspubsub v0.41.0 h1:UxNb0DiAzdnyHut6jcCG7u6lsB/hzxTyZ/RHWeC
|
||||
gocloud.dev/pubsub/natspubsub v0.41.0/go.mod h1:uCBKjwvIcuNuf3+ft4wUI9hPHHKQvroxq9ZPB/410ac=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.41.0 h1:RutvHbacZxlFr0t3wlr+kz63j53UOfHY3PJR8NKN1EI=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.41.0/go.mod h1:s7oQXOlQ2FOj8XmYMv5Ocgs1t+8hIXfsKaWGgECM9SQ=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
|
||||
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -1757,13 +1762,15 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1781,8 +1788,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4=
|
||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
@@ -1796,8 +1803,8 @@ golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeap
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
|
||||
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -1830,6 +1837,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1874,7 +1883,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@@ -1896,12 +1904,13 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1953,6 +1962,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -2051,14 +2062,17 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
@@ -2066,12 +2080,14 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -2092,6 +2108,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -2099,9 +2117,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -2172,6 +2189,7 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -2247,8 +2265,8 @@ google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/
|
||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
|
||||
google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4=
|
||||
google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
|
||||
google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -2386,8 +2404,8 @@ google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRx
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -2562,15 +2580,17 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
storj.io/common v0.0.0-20240812101423-26b53789c348 h1:Urs3fX+1Fyb+CFKGw0mCJV3MPR499WM+Vs6osw4Rqtk=
|
||||
storj.io/common v0.0.0-20240812101423-26b53789c348/go.mod h1:XMpwKxc04HCBl4H5IFCGv1ca5Dm0tvH4NL7Jx+JhxuA=
|
||||
storj.io/drpc v0.0.35-0.20240709171858-0075ac871661 h1:hLvEV2RMTscX3JHPd+LSQCeTt8i1Q0Yt7U2EdfyMnaQ=
|
||||
storj.io/drpc v0.0.35-0.20240709171858-0075ac871661/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg=
|
||||
storj.io/eventkit v0.0.0-20240415002644-1d9596fee086 h1:TkytkGUI6zGtH5Qx/O0VxQCcYJqOOiwRq0oMi4uM5Tg=
|
||||
storj.io/eventkit v0.0.0-20240415002644-1d9596fee086/go.mod h1:S6p41RzIBKoeGAdrziksWkiijnZXql9YcNsc23t0u+8=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
storj.io/common v0.0.0-20250605163628-70ca83b6228e h1:Ar4dEFhvK+hjTIAibwkz41A3rCY6IicqsLnvvb5M/4w=
|
||||
storj.io/common v0.0.0-20250605163628-70ca83b6228e/go.mod h1:1+Y92GXn/TiNuBny5/vJUyW7+zdOFpc8y9I7eGYPyDE=
|
||||
storj.io/drpc v0.0.35-0.20250513201419-f7819ea69b55 h1:8OE12DvUnB9lfZcHe7IDGsuhjrY9GBAr964PVHmhsro=
|
||||
storj.io/drpc v0.0.35-0.20250513201419-f7819ea69b55/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg=
|
||||
storj.io/eventkit v0.0.0-20250410172343-61f26d3de156 h1:5MZ0CyMbG6Pi0rRzUWVG6dvpXjbBYEX2oyXuj+tT+sk=
|
||||
storj.io/eventkit v0.0.0-20250410172343-61f26d3de156/go.mod h1:CpnM6kfZV58dcq3lpbo/IQ4/KoutarnTSHY0GYVwnYw=
|
||||
storj.io/infectious v0.0.2 h1:rGIdDC/6gNYAStsxsZU79D/MqFjNyJc1tsyyj9sTl7Q=
|
||||
storj.io/infectious v0.0.2/go.mod h1:QEjKKww28Sjl1x8iDsjBpOM4r1Yp8RsowNcItsZJ1Vs=
|
||||
storj.io/picobuf v0.0.3 h1:xAUPB5ZUGfxkqd3bnw3zp01kkWb9wlhg4vtZWUs2S9A=
|
||||
storj.io/picobuf v0.0.3/go.mod h1:4V4xelV1RSCck5GgmkL/Txw9l6IfX3XcBzegmL5Kudo=
|
||||
storj.io/picobuf v0.0.4 h1:qswHDla+YZ2TovGtMnU4astjvrADSIz84FXRn0qgP6o=
|
||||
storj.io/picobuf v0.0.4/go.mod h1:hSMxmZc58MS/2qSLy1I0idovlO7+6K47wIGUyRZa6mg=
|
||||
storj.io/uplink v1.13.1 h1:C8RdW/upALoCyuF16Lod9XGCXEdbJAS+ABQy9JO/0pA=
|
||||
storj.io/uplink v1.13.1/go.mod h1:x0MQr4UfFsQBwgVWZAtEsLpuwAn6dg7G0Mpne1r516E=
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
FROM golang:1.24-alpine
|
||||
|
||||
# Install necessary tools
|
||||
RUN apk add --no-cache \
|
||||
curl \
|
||||
netcat-openbsd \
|
||||
bash \
|
||||
git \
|
||||
build-base \
|
||||
ca-certificates
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy go mod files first for better caching
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy only the necessary source code for building and testing
|
||||
COPY weed/ ./weed/
|
||||
COPY test/mq/integration/ ./test/mq/integration/
|
||||
|
||||
# Build the weed binary for testing (optional - tests can use external cluster)
|
||||
RUN cd weed && CGO_ENABLED=1 GOOS=linux go build -o ../weed .
|
||||
|
||||
# Create test results directory
|
||||
RUN mkdir -p /test-results
|
||||
|
||||
# Set up environment
|
||||
ENV CGO_ENABLED=1
|
||||
ENV GOOS=linux
|
||||
ENV GO111MODULE=on
|
||||
|
||||
# Default working directory for tests
|
||||
WORKDIR /workspace
|
||||
|
||||
# Entry point for running tests - use explicit bash
|
||||
ENTRYPOINT ["/bin/bash", "-c"]
|
||||
@@ -0,0 +1,223 @@
|
||||
.PHONY: help build test test-basic test-performance test-failover test-agent clean up down logs
|
||||
|
||||
# Detect architecture and Docker platform compatibility
|
||||
ARCH := $(shell uname -m)
|
||||
OS := $(shell uname -s)
|
||||
ifeq ($(ARCH),arm64)
|
||||
ifeq ($(OS),Darwin)
|
||||
# On Apple Silicon macOS, use native arm64 for better performance
|
||||
DOCKER_PLATFORM := linux/arm64
|
||||
else
|
||||
DOCKER_PLATFORM := linux/arm64
|
||||
endif
|
||||
else
|
||||
DOCKER_PLATFORM := linux/amd64
|
||||
endif
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "SeaweedMQ Integration Test Suite"
|
||||
@echo ""
|
||||
@echo "Available targets:"
|
||||
@echo " build - Build SeaweedFS Docker images"
|
||||
@echo " test - Run all integration tests (in Docker)"
|
||||
@echo " test-basic - Run basic pub/sub tests (in Docker)"
|
||||
@echo " test-native - Run all tests natively (no Docker test container)"
|
||||
@echo " test-basic-native - Run basic tests natively (recommended for Apple Silicon)"
|
||||
@echo " test-performance - Run performance tests"
|
||||
@echo " test-failover - Run failover tests"
|
||||
@echo " test-agent - Run agent tests"
|
||||
@echo " up - Start test environment (local build)"
|
||||
@echo " up-prod - Start test environment (production images)"
|
||||
@echo " up-cluster - Start cluster only (no test runner)"
|
||||
@echo " down - Stop test environment"
|
||||
@echo " clean - Clean up test environment and results"
|
||||
@echo " logs - Show container logs"
|
||||
|
||||
# Build SeaweedFS Docker images
|
||||
build:
|
||||
@echo "Building SeaweedFS Docker image for $(DOCKER_PLATFORM)..."
|
||||
cd ../.. && docker build --platform $(DOCKER_PLATFORM) -f docker/Dockerfile.go_build -t chrislusf/seaweedfs:local .
|
||||
@echo "Building test runner image for $(DOCKER_PLATFORM)..."
|
||||
cd ../.. && docker build --platform $(DOCKER_PLATFORM) -f test/mq/Dockerfile.test -t seaweedfs-test-runner .
|
||||
|
||||
# Start the test environment
|
||||
up: build
|
||||
@echo "Starting SeaweedMQ test environment..."
|
||||
docker-compose -f docker-compose.test.yml up -d master0 master1 master2
|
||||
@echo "Waiting for masters to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.test.yml up -d volume1 volume2 volume3
|
||||
@echo "Waiting for volumes to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.test.yml up -d filer1 filer2
|
||||
@echo "Waiting for filers to be ready..."
|
||||
sleep 15
|
||||
docker-compose -f docker-compose.test.yml up -d broker1 broker2 broker3
|
||||
@echo "Waiting for brokers to be ready..."
|
||||
sleep 20
|
||||
@echo "Test environment is ready!"
|
||||
|
||||
# Start the test environment with production images (no build required)
|
||||
up-prod: build-test-runner
|
||||
@echo "Starting SeaweedMQ test environment with production images..."
|
||||
docker-compose -f docker-compose.production.yml up -d master0 master1 master2
|
||||
@echo "Waiting for masters to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.production.yml up -d volume1 volume2 volume3
|
||||
@echo "Waiting for volumes to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.production.yml up -d filer1 filer2
|
||||
@echo "Waiting for filers to be ready..."
|
||||
sleep 15
|
||||
docker-compose -f docker-compose.production.yml up -d broker1 broker2 broker3
|
||||
@echo "Waiting for brokers to be ready..."
|
||||
sleep 20
|
||||
@echo "Test environment is ready!"
|
||||
|
||||
# Build only the test runner image (for production setup)
|
||||
build-test-runner:
|
||||
@echo "Building test runner image for $(DOCKER_PLATFORM)..."
|
||||
cd ../.. && docker build --platform $(DOCKER_PLATFORM) -f test/mq/Dockerfile.test -t seaweedfs-test-runner .
|
||||
|
||||
# Start cluster only (no test runner, no build required)
|
||||
up-cluster:
|
||||
@echo "Starting SeaweedMQ cluster only..."
|
||||
docker-compose -f docker-compose.cluster.yml up -d master0 master1 master2
|
||||
@echo "Waiting for masters to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.cluster.yml up -d volume1 volume2 volume3
|
||||
@echo "Waiting for volumes to be ready..."
|
||||
sleep 10
|
||||
docker-compose -f docker-compose.cluster.yml up -d filer1 filer2
|
||||
@echo "Waiting for filers to be ready..."
|
||||
sleep 15
|
||||
docker-compose -f docker-compose.cluster.yml up -d broker1 broker2 broker3
|
||||
@echo "Waiting for brokers to be ready..."
|
||||
sleep 20
|
||||
@echo "SeaweedMQ cluster is ready!"
|
||||
@echo "Masters: http://localhost:19333, http://localhost:19334, http://localhost:19335"
|
||||
@echo "Filers: http://localhost:18888, http://localhost:18889"
|
||||
@echo "Brokers: localhost:17777, localhost:17778, localhost:17779"
|
||||
|
||||
# Stop the test environment
|
||||
down:
|
||||
@echo "Stopping SeaweedMQ test environment..."
|
||||
docker-compose -f docker-compose.test.yml down
|
||||
docker-compose -f docker-compose.production.yml down
|
||||
docker-compose -f docker-compose.cluster.yml down
|
||||
|
||||
# Clean up everything
|
||||
clean:
|
||||
@echo "Cleaning up test environment..."
|
||||
docker-compose -f docker-compose.test.yml down -v
|
||||
docker system prune -f
|
||||
sudo rm -rf /tmp/test-results/*
|
||||
|
||||
# Show container logs
|
||||
logs:
|
||||
docker-compose -f docker-compose.test.yml logs -f
|
||||
|
||||
# Run all integration tests
|
||||
test:
|
||||
@echo "Running all integration tests..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=30m ./test/mq/integration/... -args -test.parallel=4"
|
||||
|
||||
# Run basic pub/sub tests
|
||||
test-basic:
|
||||
@echo "Running basic pub/sub tests natively (no container restart)..."
|
||||
cd ../.. && SEAWEED_MASTERS="localhost:19333,localhost:19334,localhost:19335" \
|
||||
SEAWEED_BROKERS="localhost:17777,localhost:17778,localhost:17779" \
|
||||
SEAWEED_FILERS="localhost:18888,localhost:18889" \
|
||||
go test -v -timeout=10m ./test/mq/integration/ -run TestBasic
|
||||
|
||||
# Run performance tests
|
||||
test-performance:
|
||||
@echo "Running performance tests..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=20m ./test/mq/integration/ -run TestPerformance"
|
||||
|
||||
# Run failover tests
|
||||
test-failover:
|
||||
@echo "Running failover tests..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=15m ./test/mq/integration/ -run TestFailover"
|
||||
|
||||
# Run agent tests
|
||||
test-agent:
|
||||
@echo "Running agent tests..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=10m ./test/mq/integration/ -run TestAgent"
|
||||
|
||||
# Development targets (run tests natively without Docker container)
|
||||
test-dev:
|
||||
@echo "Running tests in development mode (using local binaries)..."
|
||||
SEAWEED_MASTERS="localhost:19333,localhost:19334,localhost:19335" \
|
||||
SEAWEED_BROKERS="localhost:17777,localhost:17778,localhost:17779" \
|
||||
SEAWEED_FILERS="localhost:18888,localhost:18889" \
|
||||
go test -v -timeout=10m ./integration/...
|
||||
|
||||
# Native test running (no Docker container for tests)
|
||||
test-native:
|
||||
@echo "Running tests natively (without Docker container for tests)..."
|
||||
cd ../.. && SEAWEED_MASTERS="localhost:19333,localhost:19334,localhost:19335" \
|
||||
SEAWEED_BROKERS="localhost:17777,localhost:17778,localhost:17779" \
|
||||
SEAWEED_FILERS="localhost:18888,localhost:18889" \
|
||||
go test -v -timeout=10m ./test/mq/integration/...
|
||||
|
||||
# Basic native tests
|
||||
test-basic-native:
|
||||
@echo "Running basic tests natively..."
|
||||
cd ../.. && SEAWEED_MASTERS="localhost:19333,localhost:19334,localhost:19335" \
|
||||
SEAWEED_BROKERS="localhost:17777,localhost:17778,localhost:17779" \
|
||||
SEAWEED_FILERS="localhost:18888,localhost:18889" \
|
||||
go test -v -timeout=10m ./test/mq/integration/ -run TestBasic
|
||||
|
||||
# Quick smoke test
|
||||
smoke-test:
|
||||
@echo "Running smoke test..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=5m ./test/mq/integration/ -run TestBasicPublishSubscribe"
|
||||
|
||||
# Performance benchmarks
|
||||
benchmark:
|
||||
@echo "Running performance benchmarks..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=30m -bench=. ./test/mq/integration/..."
|
||||
|
||||
# Check test environment health
|
||||
health:
|
||||
@echo "Checking test environment health..."
|
||||
@echo "Masters:"
|
||||
@curl -s http://localhost:19333/cluster/status || echo "Master 0 not accessible"
|
||||
@curl -s http://localhost:19334/cluster/status || echo "Master 1 not accessible"
|
||||
@curl -s http://localhost:19335/cluster/status || echo "Master 2 not accessible"
|
||||
@echo ""
|
||||
@echo "Filers:"
|
||||
@curl -s http://localhost:18888/ || echo "Filer 1 not accessible"
|
||||
@curl -s http://localhost:18889/ || echo "Filer 2 not accessible"
|
||||
@echo ""
|
||||
@echo "Brokers:"
|
||||
@nc -z localhost 17777 && echo "Broker 1 accessible" || echo "Broker 1 not accessible"
|
||||
@nc -z localhost 17778 && echo "Broker 2 accessible" || echo "Broker 2 not accessible"
|
||||
@nc -z localhost 17779 && echo "Broker 3 accessible" || echo "Broker 3 not accessible"
|
||||
|
||||
# Generate test reports
|
||||
report:
|
||||
@echo "Generating test reports..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=30m ./test/mq/integration/... -json > /test-results/test-report.json"
|
||||
|
||||
# Load testing
|
||||
load-test:
|
||||
@echo "Running load tests..."
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -timeout=45m ./test/mq/integration/ -run TestLoad"
|
||||
|
||||
# View monitoring dashboards
|
||||
monitoring:
|
||||
@echo "Starting monitoring stack..."
|
||||
docker-compose -f docker-compose.test.yml up -d prometheus grafana
|
||||
@echo "Prometheus: http://localhost:19090"
|
||||
@echo "Grafana: http://localhost:13000 (admin/admin)"
|
||||
@@ -0,0 +1,414 @@
|
||||
# SeaweedMQ Integration Test Suite
|
||||
|
||||
This directory contains a comprehensive integration test suite for SeaweedMQ, designed to validate all critical functionalities from basic pub/sub operations to advanced features like auto-scaling, failover, and performance testing.
|
||||
|
||||
## Overview
|
||||
|
||||
The integration test suite provides:
|
||||
|
||||
- **Automated Environment Setup**: Docker Compose based test clusters
|
||||
- **Comprehensive Test Coverage**: Basic pub/sub, scaling, failover, performance
|
||||
- **Monitoring & Metrics**: Prometheus and Grafana integration
|
||||
- **CI/CD Ready**: Configurable for continuous integration pipelines
|
||||
- **Load Testing**: Performance benchmarks and stress tests
|
||||
|
||||
## Architecture
|
||||
|
||||
The test environment consists of:
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Master Cluster │ │ Volume Servers │ │ Filer Cluster │
|
||||
│ (3 nodes) │ │ (3 nodes) │ │ (2 nodes) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Broker Cluster │ │ Test Framework │ │ Monitoring │
|
||||
│ (3 nodes) │ │ (Go Tests) │ │ (Prometheus + │
|
||||
└─────────────────┘ └─────────────────┘ │ Grafana) │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker and Docker Compose
|
||||
- Go 1.21+
|
||||
- Make
|
||||
- 8GB+ RAM recommended
|
||||
- 20GB+ disk space for test data
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Choose one of three approaches:
|
||||
|
||||
#### Option 1: Quick Cluster Setup (Fastest)
|
||||
Just starts a SeaweedMQ cluster - no test runner, no build required.
|
||||
|
||||
1. **Start Cluster**:
|
||||
```bash
|
||||
cd test/mq
|
||||
make up-cluster
|
||||
```
|
||||
|
||||
2. **Test manually** or with your own code against:
|
||||
- Masters: http://localhost:19333, http://localhost:19334, http://localhost:19335
|
||||
- Brokers: localhost:17777, localhost:17778, localhost:17779
|
||||
- Filers: http://localhost:18888, http://localhost:18889
|
||||
|
||||
#### Option 2: Use Production Images (Recommended for testing)
|
||||
Uses official SeaweedFS images from Docker Hub with test runner.
|
||||
|
||||
1. **Start Test Environment**:
|
||||
```bash
|
||||
cd test/mq
|
||||
make up-prod
|
||||
```
|
||||
|
||||
2. **Run Tests**:
|
||||
```bash
|
||||
make test-basic # Basic pub/sub tests
|
||||
```
|
||||
|
||||
#### Option 3: Build from Source (Development)
|
||||
Builds SeaweedFS from your local source code to test latest changes.
|
||||
|
||||
1. **Start Test Environment**:
|
||||
```bash
|
||||
cd test/mq
|
||||
make up # This will build and start
|
||||
```
|
||||
|
||||
2. **Run Tests**:
|
||||
```bash
|
||||
make test-basic # Basic pub/sub tests
|
||||
```
|
||||
|
||||
#### Common Commands
|
||||
|
||||
3. **Run All Tests**:
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
4. **Run Specific Test Categories**:
|
||||
```bash
|
||||
make test-performance # Performance tests
|
||||
make test-failover # Failover tests
|
||||
make test-agent # Agent tests
|
||||
```
|
||||
|
||||
5. **Quick Smoke Test**:
|
||||
```bash
|
||||
make smoke-test
|
||||
```
|
||||
|
||||
6. **Check Health**:
|
||||
```bash
|
||||
make health
|
||||
```
|
||||
|
||||
7. **Clean Up**:
|
||||
```bash
|
||||
make down
|
||||
```
|
||||
|
||||
## Test Categories
|
||||
|
||||
### 1. Basic Functionality Tests
|
||||
|
||||
**File**: `integration/basic_pubsub_test.go`
|
||||
|
||||
- **TestBasicPublishSubscribe**: Basic message publishing and consumption
|
||||
- **TestMultipleConsumers**: Load balancing across multiple consumers
|
||||
- **TestMessageOrdering**: FIFO ordering within partitions
|
||||
- **TestSchemaValidation**: Schema validation and complex nested structures
|
||||
|
||||
### 2. Partitioning and Scaling Tests
|
||||
|
||||
**File**: `integration/scaling_test.go` (to be implemented)
|
||||
|
||||
- **TestPartitionDistribution**: Message distribution across partitions
|
||||
- **TestAutoSplitMerge**: Automatic partition split/merge based on load
|
||||
- **TestBrokerScaling**: Adding/removing brokers during operation
|
||||
- **TestLoadBalancing**: Even load distribution verification
|
||||
|
||||
### 3. Failover and Reliability Tests
|
||||
|
||||
**File**: `integration/failover_test.go` (to be implemented)
|
||||
|
||||
- **TestBrokerFailover**: Leader failover scenarios
|
||||
- **TestBrokerRecovery**: Recovery from broker failures
|
||||
- **TestMessagePersistence**: Data durability across restarts
|
||||
- **TestFollowerReplication**: Leader-follower consistency
|
||||
|
||||
### 4. Performance Tests
|
||||
|
||||
**File**: `integration/performance_test.go` (to be implemented)
|
||||
|
||||
- **TestHighThroughputPublish**: High-volume message publishing
|
||||
- **TestHighThroughputSubscribe**: High-volume message consumption
|
||||
- **TestLatencyMeasurement**: End-to-end latency analysis
|
||||
- **TestResourceUtilization**: CPU, memory, and disk usage
|
||||
|
||||
### 5. Agent Tests
|
||||
|
||||
**File**: `integration/agent_test.go` (to be implemented)
|
||||
|
||||
- **TestAgentPublishSessions**: Session management for publishers
|
||||
- **TestAgentSubscribeSessions**: Session management for subscribers
|
||||
- **TestAgentFailover**: Agent reconnection and failover
|
||||
- **TestAgentConcurrency**: Concurrent session handling
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The test framework supports configuration via environment variables:
|
||||
|
||||
```bash
|
||||
# Cluster endpoints
|
||||
SEAWEED_MASTERS="master0:9333,master1:9334,master2:9335"
|
||||
SEAWEED_BROKERS="broker1:17777,broker2:17778,broker3:17779"
|
||||
SEAWEED_FILERS="filer1:8888,filer2:8889"
|
||||
|
||||
# Test configuration
|
||||
GO_TEST_TIMEOUT="30m"
|
||||
TEST_RESULTS_DIR="/test-results"
|
||||
```
|
||||
|
||||
### Docker Compose Override
|
||||
|
||||
Create `docker-compose.override.yml` to customize the test environment:
|
||||
|
||||
```yaml
|
||||
version: '3.9'
|
||||
services:
|
||||
broker1:
|
||||
environment:
|
||||
- CUSTOM_ENV_VAR=value
|
||||
test-runner:
|
||||
volumes:
|
||||
- ./custom-config:/config
|
||||
```
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
### Prometheus Metrics
|
||||
|
||||
Access Prometheus at: http://localhost:19090
|
||||
|
||||
Key metrics to monitor:
|
||||
- Message throughput: `seaweedmq_messages_published_total`
|
||||
- Consumer lag: `seaweedmq_consumer_lag_seconds`
|
||||
- Broker health: `seaweedmq_broker_health`
|
||||
- Resource usage: `seaweedfs_disk_usage_bytes`
|
||||
|
||||
### Grafana Dashboards
|
||||
|
||||
Access Grafana at: http://localhost:13000 (admin/admin)
|
||||
|
||||
Pre-configured dashboards:
|
||||
- **SeaweedMQ Overview**: System health and throughput
|
||||
- **Performance Metrics**: Latency and resource usage
|
||||
- **Error Analysis**: Error rates and failure patterns
|
||||
|
||||
## Development
|
||||
|
||||
### Writing New Tests
|
||||
|
||||
1. **Create Test File**:
|
||||
```bash
|
||||
touch integration/my_new_test.go
|
||||
```
|
||||
|
||||
2. **Use Test Framework**:
|
||||
```go
|
||||
func TestMyFeature(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
// Your test logic here
|
||||
}
|
||||
```
|
||||
|
||||
3. **Run Specific Test**:
|
||||
```bash
|
||||
go test -v ./integration/ -run TestMyFeature
|
||||
```
|
||||
|
||||
### Test Framework Components
|
||||
|
||||
**IntegrationTestSuite**: Base test framework with cluster management
|
||||
**MessageCollector**: Utility for collecting and verifying received messages
|
||||
**TestMessage**: Standard message structure for testing
|
||||
**Schema Builders**: Helpers for creating test schemas
|
||||
|
||||
### Local Development
|
||||
|
||||
Run tests against a local SeaweedMQ cluster:
|
||||
|
||||
```bash
|
||||
make test-dev
|
||||
```
|
||||
|
||||
This uses local binaries instead of Docker containers.
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
### GitHub Actions Example
|
||||
|
||||
```yaml
|
||||
name: Integration Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
integration-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
- name: Run Integration Tests
|
||||
run: |
|
||||
cd test/mq
|
||||
make test
|
||||
```
|
||||
|
||||
### Jenkins Pipeline
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Setup') {
|
||||
steps {
|
||||
sh 'cd test/mq && make up'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'cd test/mq && make test'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
sh 'cd test/mq && make down'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Port Conflicts**:
|
||||
```bash
|
||||
# Check port usage
|
||||
netstat -tulpn | grep :19333
|
||||
|
||||
# Kill conflicting processes
|
||||
sudo kill -9 $(lsof -t -i:19333)
|
||||
```
|
||||
|
||||
2. **Docker Resource Issues**:
|
||||
```bash
|
||||
# Increase Docker memory (8GB+)
|
||||
# Clean up Docker resources
|
||||
docker system prune -a
|
||||
```
|
||||
|
||||
3. **Test Timeouts**:
|
||||
```bash
|
||||
# Increase timeout
|
||||
GO_TEST_TIMEOUT=60m make test
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Run tests with verbose logging:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.test.yml run --rm test-runner \
|
||||
sh -c "go test -v -race ./test/mq/integration/... -args -test.v"
|
||||
```
|
||||
|
||||
### Container Logs
|
||||
|
||||
View real-time logs:
|
||||
|
||||
```bash
|
||||
make logs
|
||||
|
||||
# Or specific service
|
||||
docker-compose -f docker-compose.test.yml logs -f broker1
|
||||
```
|
||||
|
||||
## Performance Benchmarks
|
||||
|
||||
### Throughput Benchmarks
|
||||
|
||||
```bash
|
||||
make benchmark
|
||||
```
|
||||
|
||||
Expected performance (on 8-core, 16GB RAM):
|
||||
- **Publish Throughput**: 50K+ messages/second/broker
|
||||
- **Subscribe Throughput**: 100K+ messages/second/broker
|
||||
- **End-to-End Latency**: P95 < 100ms
|
||||
- **Storage Efficiency**: < 20% overhead
|
||||
|
||||
### Load Testing
|
||||
|
||||
```bash
|
||||
make load-test
|
||||
```
|
||||
|
||||
Stress tests with:
|
||||
- 1M+ messages
|
||||
- 100+ concurrent producers
|
||||
- 50+ concurrent consumers
|
||||
- Multiple topic scenarios
|
||||
|
||||
## Contributing
|
||||
|
||||
### Test Guidelines
|
||||
|
||||
1. **Test Isolation**: Each test should be independent
|
||||
2. **Resource Cleanup**: Always clean up resources in test teardown
|
||||
3. **Timeouts**: Set appropriate timeouts for operations
|
||||
4. **Error Handling**: Test both success and failure scenarios
|
||||
5. **Documentation**: Document test purpose and expected behavior
|
||||
|
||||
### Code Style
|
||||
|
||||
- Follow Go testing conventions
|
||||
- Use testify for assertions
|
||||
- Include setup/teardown in test functions
|
||||
- Use descriptive test names
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Chaos engineering tests (network partitions, node failures)
|
||||
- [ ] Multi-datacenter deployment testing
|
||||
- [ ] Schema evolution compatibility tests
|
||||
- [ ] Security and authentication tests
|
||||
- [ ] Performance regression detection
|
||||
- [ ] Automated load pattern generation
|
||||
|
||||
## Support
|
||||
|
||||
For issues and questions:
|
||||
- Check existing GitHub issues
|
||||
- Review SeaweedMQ documentation
|
||||
- Join SeaweedFS community discussions
|
||||
|
||||
---
|
||||
|
||||
*This integration test suite ensures SeaweedMQ's reliability, performance, and functionality across all critical use cases and failure scenarios.*
|
||||
@@ -0,0 +1,165 @@
|
||||
services:
|
||||
# Masters
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19333:9333"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master0:/data
|
||||
command: "master -port=9333 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -ip=master0 -defaultReplication=001"
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master0:9333/cluster/status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19334:9334"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master1:/data
|
||||
command: "master -port=9334 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -ip=master1 -defaultReplication=001"
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master1:9334/cluster/status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19335:9335"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master2:/data
|
||||
command: "master -port=9335 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -ip=master2 -defaultReplication=001"
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master2:9335/cluster/status"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# Volume Servers
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18080:8080"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume1:/data
|
||||
command: "volume -port=8080 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18081:8081"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume2:/data
|
||||
command: "volume -port=8081 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18082:8082"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume3:/data
|
||||
command: "volume -port=8082 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
# Filers
|
||||
filer1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18888:8888"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/filer1:/data
|
||||
command: "filer -port=8888 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- volume1
|
||||
- volume2
|
||||
- volume3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
filer2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18889:8889"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/filer2:/data
|
||||
command: "filer -port=8889 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- volume1
|
||||
- volume2
|
||||
- volume3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
# Message Queue Brokers
|
||||
broker1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17777:17777"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker1:/data
|
||||
command: "mq.broker -port=17777 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
broker2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17778:17778"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker2:/data
|
||||
command: "mq.broker -port=17778 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
broker3:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17779:17779"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker3:/data
|
||||
command: "mq.broker -port=17779 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
|
||||
networks:
|
||||
seaweedfs-test:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,260 @@
|
||||
services:
|
||||
# Masters
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19333:19333"
|
||||
- "9333:9333"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master0:/data
|
||||
command: "master -port=9333 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -defaultReplication=001"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 7
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 6
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master0:9333/cluster/status"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19334:9334"
|
||||
- "9334:9334"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master1:/data
|
||||
command: "master -port=9334 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -defaultReplication=001"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 7
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 6
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master1:9334/cluster/status"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "19335:9335"
|
||||
- "9335:9335"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/master2:/data
|
||||
command: "master -port=9335 -mdir=/data -peers=master0:9333,master1:9334,master2:9335 -defaultReplication=001"
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 7
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 6
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master2:9335/cluster/status"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
# Volume Servers
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18080:8080"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume1:/data
|
||||
command: "volume -port=8080 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
master1:
|
||||
condition: service_healthy
|
||||
master2:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_VOLUME_MAX: 100
|
||||
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18081:8081"
|
||||
- "8081:8081"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume2:/data
|
||||
command: "volume -port=8081 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
master1:
|
||||
condition: service_healthy
|
||||
master2:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_VOLUME_MAX: 100
|
||||
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18082:8082"
|
||||
- "8082:8082"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/volume3:/data
|
||||
command: "volume -port=8082 -mserver=master0:9333,master1:9334,master2:9335 -dir=/data"
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
master1:
|
||||
condition: service_healthy
|
||||
master2:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_VOLUME_MAX: 100
|
||||
|
||||
# Filers
|
||||
filer1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18888:8888"
|
||||
- "8888:8888"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/filer1:/data
|
||||
command: "filer -port=8888 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- volume1
|
||||
- volume2
|
||||
- volume3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_LEVELDB2_DIR: "/data/filerldb2"
|
||||
|
||||
filer2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "18889:8889"
|
||||
- "8889:8889"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/filer2:/data
|
||||
command: "filer -port=8889 -master=master0:9333,master1:9334,master2:9335"
|
||||
depends_on:
|
||||
- volume1
|
||||
- volume2
|
||||
- volume3
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_LEVELDB2_DIR: "/data/filerldb2"
|
||||
|
||||
# Message Queue Brokers
|
||||
broker1:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17777:17777"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker1:/data
|
||||
command: "mq.broker -port=17777 -filer=filer1:8888,filer2:8889"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_MQ_BROKER_CPU_PERCENT: 80
|
||||
|
||||
broker2:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17778:17778"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker2:/data
|
||||
command: "mq.broker -port=17778 -filer=filer1:8888,filer2:8889"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_MQ_BROKER_CPU_PERCENT: 80
|
||||
|
||||
broker3:
|
||||
image: chrislusf/seaweedfs:latest
|
||||
ports:
|
||||
- "17779:17779"
|
||||
volumes:
|
||||
- /tmp/seaweedfs-test/broker3:/data
|
||||
command: "mq.broker -port=17779 -filer=filer1:8888,filer2:8889"
|
||||
depends_on:
|
||||
- filer1
|
||||
- filer2
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
WEED_MQ_BROKER_CPU_PERCENT: 80
|
||||
|
||||
# Test Runner
|
||||
test-runner:
|
||||
image: seaweedfs-test-runner
|
||||
volumes:
|
||||
- ../..:/workspace
|
||||
- /tmp/test-results:/test-results
|
||||
working_dir: /workspace
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
environment:
|
||||
- SEAWEED_MASTERS=master0:9333,master1:9334,master2:9335
|
||||
- SEAWEED_BROKERS=broker1:17777,broker2:17778,broker3:17779
|
||||
- SEAWEED_FILERS=filer1:8888,filer2:8889
|
||||
- GO111MODULE=on
|
||||
- CGO_ENABLED=0
|
||||
depends_on:
|
||||
- broker1
|
||||
- broker2
|
||||
- broker3
|
||||
|
||||
# Monitoring
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
ports:
|
||||
- "19090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
depends_on:
|
||||
- master0
|
||||
- master1
|
||||
- master2
|
||||
- volume1
|
||||
- volume2
|
||||
- volume3
|
||||
- filer1
|
||||
- filer2
|
||||
- broker1
|
||||
- broker2
|
||||
- broker3
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
ports:
|
||||
- "13000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
networks:
|
||||
- seaweedfs-test
|
||||
depends_on:
|
||||
- prometheus
|
||||
|
||||
networks:
|
||||
seaweedfs-test:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,341 @@
|
||||
services:
|
||||
# Master cluster for coordination and metadata
|
||||
master0:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-master0
|
||||
ports:
|
||||
- "19333:9333"
|
||||
- "29333:19333"
|
||||
command: >
|
||||
-v=1
|
||||
master
|
||||
-volumeSizeLimitMB=100
|
||||
-resumeState=false
|
||||
-ip=master0
|
||||
-port=9333
|
||||
-peers=master0:9333,master1:9334,master2:9335
|
||||
-mdir=/tmp/master0
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://master0:9333/cluster/status"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
master1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-master1
|
||||
ports:
|
||||
- "19334:9334"
|
||||
- "29334:19334"
|
||||
command: >
|
||||
-v=1
|
||||
master
|
||||
-volumeSizeLimitMB=100
|
||||
-resumeState=false
|
||||
-ip=master1
|
||||
-port=9334
|
||||
-peers=master0:9333,master1:9334,master2:9335
|
||||
-mdir=/tmp/master1
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
- master0
|
||||
|
||||
master2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-master2
|
||||
ports:
|
||||
- "19335:9335"
|
||||
- "29335:19335"
|
||||
command: >
|
||||
-v=1
|
||||
master
|
||||
-volumeSizeLimitMB=100
|
||||
-resumeState=false
|
||||
-ip=master2
|
||||
-port=9335
|
||||
-peers=master0:9333,master1:9334,master2:9335
|
||||
-mdir=/tmp/master2
|
||||
environment:
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_1: 1
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_2: 2
|
||||
WEED_MASTER_VOLUME_GROWTH_COPY_OTHER: 1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
- master0
|
||||
|
||||
# Volume servers for data storage
|
||||
volume1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-volume1
|
||||
ports:
|
||||
- "18080:8080"
|
||||
- "28080:18080"
|
||||
volumes:
|
||||
- volume1-data:/data/volume1
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command: >
|
||||
"mkdir -p /data/volume1 && exec weed -v=1
|
||||
volume
|
||||
-dataCenter=dc1
|
||||
-rack=rack1
|
||||
-mserver=master0:9333,master1:9334,master2:9335
|
||||
-port=8080
|
||||
-ip=volume1
|
||||
-publicUrl=localhost:18080
|
||||
-preStopSeconds=1
|
||||
-dir=/data/volume1"
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
|
||||
volume2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-volume2
|
||||
ports:
|
||||
- "18081:8081"
|
||||
- "28081:18081"
|
||||
volumes:
|
||||
- volume2-data:/data/volume2
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command: >
|
||||
"mkdir -p /data/volume2 && exec weed -v=1
|
||||
volume
|
||||
-dataCenter=dc1
|
||||
-rack=rack2
|
||||
-mserver=master0:9333,master1:9334,master2:9335
|
||||
-port=8081
|
||||
-ip=volume2
|
||||
-publicUrl=localhost:18081
|
||||
-preStopSeconds=1
|
||||
-dir=/data/volume2"
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
|
||||
volume3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-volume3
|
||||
ports:
|
||||
- "18082:8082"
|
||||
- "28082:18082"
|
||||
volumes:
|
||||
- volume3-data:/data/volume3
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command: >
|
||||
"mkdir -p /data/volume3 && exec weed -v=1
|
||||
volume
|
||||
-dataCenter=dc2
|
||||
-rack=rack1
|
||||
-mserver=master0:9333,master1:9334,master2:9335
|
||||
-port=8082
|
||||
-ip=volume3
|
||||
-publicUrl=localhost:18082
|
||||
-preStopSeconds=1
|
||||
-dir=/data/volume3"
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
|
||||
# Filer servers for metadata
|
||||
filer1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-filer1
|
||||
ports:
|
||||
- "18888:8888"
|
||||
- "28888:18888"
|
||||
command: >
|
||||
-v=1
|
||||
filer
|
||||
-defaultReplicaPlacement=100
|
||||
-master=master0:9333,master1:9334,master2:9335
|
||||
-port=8888
|
||||
-ip=filer1
|
||||
-dataCenter=dc1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
master0:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://filer1:8888/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
filer2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-filer2
|
||||
ports:
|
||||
- "18889:8889"
|
||||
- "28889:18889"
|
||||
command: >
|
||||
-v=1
|
||||
filer
|
||||
-defaultReplicaPlacement=100
|
||||
-master=master0:9333,master1:9334,master2:9335
|
||||
-port=8889
|
||||
-ip=filer2
|
||||
-dataCenter=dc2
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
filer1:
|
||||
condition: service_healthy
|
||||
|
||||
# Message Queue Brokers
|
||||
broker1:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-broker1
|
||||
ports:
|
||||
- "17777:17777"
|
||||
command: >
|
||||
-v=1
|
||||
mq.broker
|
||||
-master=master0:9333,master1:9334,master2:9335
|
||||
-port=17777
|
||||
-ip=127.0.0.1
|
||||
-dataCenter=dc1
|
||||
-rack=rack1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
filer1:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "localhost", "17777"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
broker2:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-broker2
|
||||
ports:
|
||||
- "17778:17778"
|
||||
command: >
|
||||
-v=1
|
||||
mq.broker
|
||||
-master=master0:9333,master1:9334,master2:9335
|
||||
-port=17778
|
||||
-ip=127.0.0.1
|
||||
-dataCenter=dc1
|
||||
-rack=rack2
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
broker1:
|
||||
condition: service_healthy
|
||||
|
||||
broker3:
|
||||
image: chrislusf/seaweedfs:local
|
||||
container_name: test-broker3
|
||||
ports:
|
||||
- "17779:17779"
|
||||
command: >
|
||||
-v=1
|
||||
mq.broker
|
||||
-master=master0:9333,master1:9334,master2:9335
|
||||
-port=17779
|
||||
-ip=127.0.0.1
|
||||
-dataCenter=dc2
|
||||
-rack=rack1
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
broker1:
|
||||
condition: service_healthy
|
||||
|
||||
# Test runner container
|
||||
test-runner:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: test/mq/Dockerfile.test
|
||||
container_name: test-runner
|
||||
volumes:
|
||||
- ../../:/app
|
||||
- /tmp/test-results:/test-results
|
||||
working_dir: /app
|
||||
environment:
|
||||
- SEAWEED_MASTERS=master0:9333,master1:9334,master2:9335
|
||||
- SEAWEED_BROKERS=broker1:17777,broker2:17778,broker3:17779
|
||||
- SEAWEED_FILERS=filer1:8888,filer2:8889
|
||||
- TEST_RESULTS_DIR=/test-results
|
||||
- GO_TEST_TIMEOUT=30m
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
depends_on:
|
||||
broker1:
|
||||
condition: service_healthy
|
||||
broker2:
|
||||
condition: service_started
|
||||
broker3:
|
||||
condition: service_started
|
||||
command: >
|
||||
sh -c "
|
||||
echo 'Waiting for cluster to be ready...' &&
|
||||
sleep 30 &&
|
||||
echo 'Running integration tests...' &&
|
||||
go test -v -timeout=30m ./test/mq/integration/... -args -test.parallel=4
|
||||
"
|
||||
|
||||
# Monitoring and metrics
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: test-prometheus
|
||||
ports:
|
||||
- "19090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: test-grafana
|
||||
ports:
|
||||
- "13000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- grafana-storage:/var/lib/grafana
|
||||
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
|
||||
- ./grafana/datasources:/etc/grafana/provisioning/datasources
|
||||
networks:
|
||||
- seaweedmq-test
|
||||
|
||||
networks:
|
||||
seaweedmq-test:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
grafana-storage:
|
||||
volume1-data:
|
||||
volume2-data:
|
||||
volume3-data:
|
||||
@@ -0,0 +1,339 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/schema"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBasicPublishSubscribe(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
namespace := "test"
|
||||
topicName := fmt.Sprintf("basic-pubsub-%d", time.Now().UnixNano()) // Unique topic name per run
|
||||
testSchema := CreateTestSchema()
|
||||
messageCount := 10
|
||||
|
||||
// Create publisher
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 1,
|
||||
PublisherName: "basic-publisher",
|
||||
RecordType: testSchema,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create subscriber
|
||||
subConfig := &SubscriberTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
ConsumerGroup: "test-group",
|
||||
ConsumerInstanceId: "consumer-1",
|
||||
MaxPartitionCount: 1,
|
||||
SlidingWindowSize: 10,
|
||||
OffsetType: schema_pb.OffsetType_RESET_TO_EARLIEST,
|
||||
}
|
||||
|
||||
subscriber, err := suite.CreateSubscriber(subConfig)
|
||||
require.NoError(t, err, "Failed to create subscriber")
|
||||
|
||||
// Set up message collector
|
||||
collector := NewMessageCollector(messageCount)
|
||||
subscriber.SetOnDataMessageFn(func(m *mq_pb.SubscribeMessageResponse_Data) {
|
||||
t.Logf("[Subscriber] Received message with key: %s, ts: %d", string(m.Data.Key), m.Data.TsNs)
|
||||
collector.AddMessage(TestMessage{
|
||||
ID: fmt.Sprintf("msg-%d", len(collector.GetMessages())),
|
||||
Content: m.Data.Value,
|
||||
Timestamp: time.Unix(0, m.Data.TsNs),
|
||||
Key: m.Data.Key,
|
||||
})
|
||||
})
|
||||
|
||||
// Start subscriber
|
||||
go func() {
|
||||
err := subscriber.Subscribe()
|
||||
if err != nil {
|
||||
t.Logf("Subscriber error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for subscriber to be ready
|
||||
t.Logf("[Test] Waiting for subscriber to be ready...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Publish test messages
|
||||
for i := 0; i < messageCount; i++ {
|
||||
record := schema.RecordBegin().
|
||||
SetString("id", fmt.Sprintf("msg-%d", i)).
|
||||
SetInt64("timestamp", time.Now().UnixNano()).
|
||||
SetString("content", fmt.Sprintf("Test message %d", i)).
|
||||
SetInt32("sequence", int32(i)).
|
||||
RecordEnd()
|
||||
|
||||
key := []byte(fmt.Sprintf("key-%d", i))
|
||||
t.Logf("[Publisher] Publishing message %d with key: %s", i, string(key))
|
||||
err := publisher.PublishRecord(key, record)
|
||||
require.NoError(t, err, "Failed to publish message %d", i)
|
||||
}
|
||||
|
||||
t.Logf("[Test] Waiting for messages to be received...")
|
||||
messages := collector.WaitForMessages(30 * time.Second)
|
||||
t.Logf("[Test] WaitForMessages returned. Received %d messages.", len(messages))
|
||||
|
||||
// Verify all messages were received
|
||||
assert.Len(t, messages, messageCount, "Expected %d messages, got %d", messageCount, len(messages))
|
||||
|
||||
// Verify message content
|
||||
for i, msg := range messages {
|
||||
assert.NotEmpty(t, msg.Content, "Message %d should have content", i)
|
||||
assert.NotEmpty(t, msg.Key, "Message %d should have key", i)
|
||||
}
|
||||
|
||||
t.Logf("[Test] TestBasicPublishSubscribe completed.")
|
||||
}
|
||||
|
||||
func TestMultipleConsumers(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
namespace := "test"
|
||||
topicName := "multi-consumer"
|
||||
testSchema := CreateTestSchema()
|
||||
messageCount := 20
|
||||
consumerCount := 3
|
||||
|
||||
// Create publisher
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 3, // Multiple partitions for load distribution
|
||||
PublisherName: "multi-publisher",
|
||||
RecordType: testSchema,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create multiple consumers
|
||||
collectors := make([]*MessageCollector, consumerCount)
|
||||
for i := 0; i < consumerCount; i++ {
|
||||
collectors[i] = NewMessageCollector(messageCount / consumerCount) // Expect roughly equal distribution
|
||||
|
||||
subConfig := &SubscriberTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
ConsumerGroup: "multi-consumer-group", // Same group for load balancing
|
||||
ConsumerInstanceId: fmt.Sprintf("consumer-%d", i),
|
||||
MaxPartitionCount: 1,
|
||||
SlidingWindowSize: 10,
|
||||
OffsetType: schema_pb.OffsetType_RESET_TO_EARLIEST,
|
||||
}
|
||||
|
||||
subscriber, err := suite.CreateSubscriber(subConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up message collection for this consumer
|
||||
collectorIndex := i
|
||||
subscriber.SetOnDataMessageFn(func(m *mq_pb.SubscribeMessageResponse_Data) {
|
||||
collectors[collectorIndex].AddMessage(TestMessage{
|
||||
ID: fmt.Sprintf("consumer-%d-msg-%d", collectorIndex, len(collectors[collectorIndex].GetMessages())),
|
||||
Content: m.Data.Value,
|
||||
Timestamp: time.Unix(0, m.Data.TsNs),
|
||||
Key: m.Data.Key,
|
||||
})
|
||||
})
|
||||
|
||||
// Start subscriber
|
||||
go func() {
|
||||
subscriber.Subscribe()
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for subscribers to be ready
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Publish messages with different keys to distribute across partitions
|
||||
for i := 0; i < messageCount; i++ {
|
||||
record := schema.RecordBegin().
|
||||
SetString("id", fmt.Sprintf("multi-msg-%d", i)).
|
||||
SetInt64("timestamp", time.Now().UnixNano()).
|
||||
SetString("content", fmt.Sprintf("Multi consumer test message %d", i)).
|
||||
SetInt32("sequence", int32(i)).
|
||||
RecordEnd()
|
||||
|
||||
key := []byte(fmt.Sprintf("partition-key-%d", i%3)) // Distribute across 3 partitions
|
||||
err := publisher.PublishRecord(key, record)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Wait for all messages to be consumed
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
// Verify message distribution
|
||||
totalReceived := 0
|
||||
for i, collector := range collectors {
|
||||
messages := collector.GetMessages()
|
||||
t.Logf("Consumer %d received %d messages", i, len(messages))
|
||||
totalReceived += len(messages)
|
||||
}
|
||||
|
||||
// All messages should be consumed across all consumers
|
||||
assert.Equal(t, messageCount, totalReceived, "Total messages received should equal messages sent")
|
||||
}
|
||||
|
||||
func TestMessageOrdering(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
namespace := "test"
|
||||
topicName := "ordering-test"
|
||||
testSchema := CreateTestSchema()
|
||||
messageCount := 15
|
||||
|
||||
// Create publisher
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 1, // Single partition to guarantee ordering
|
||||
PublisherName: "ordering-publisher",
|
||||
RecordType: testSchema,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create subscriber
|
||||
subConfig := &SubscriberTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
ConsumerGroup: "ordering-group",
|
||||
ConsumerInstanceId: "ordering-consumer",
|
||||
MaxPartitionCount: 1,
|
||||
SlidingWindowSize: 5,
|
||||
OffsetType: schema_pb.OffsetType_RESET_TO_EARLIEST,
|
||||
}
|
||||
|
||||
subscriber, err := suite.CreateSubscriber(subConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up message collector
|
||||
collector := NewMessageCollector(messageCount)
|
||||
subscriber.SetOnDataMessageFn(func(m *mq_pb.SubscribeMessageResponse_Data) {
|
||||
collector.AddMessage(TestMessage{
|
||||
ID: fmt.Sprintf("ordered-msg"),
|
||||
Content: m.Data.Value,
|
||||
Timestamp: time.Unix(0, m.Data.TsNs),
|
||||
Key: m.Data.Key,
|
||||
})
|
||||
})
|
||||
|
||||
// Start subscriber
|
||||
go func() {
|
||||
subscriber.Subscribe()
|
||||
}()
|
||||
|
||||
// Wait for consumer to be ready
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Publish messages with same key to ensure they go to same partition
|
||||
publishTimes := make([]time.Time, messageCount)
|
||||
for i := 0; i < messageCount; i++ {
|
||||
publishTimes[i] = time.Now()
|
||||
|
||||
record := schema.RecordBegin().
|
||||
SetString("id", fmt.Sprintf("ordered-%d", i)).
|
||||
SetInt64("timestamp", publishTimes[i].UnixNano()).
|
||||
SetString("content", fmt.Sprintf("Ordered message %d", i)).
|
||||
SetInt32("sequence", int32(i)).
|
||||
RecordEnd()
|
||||
|
||||
key := []byte("same-partition-key") // Same key ensures same partition
|
||||
err := publisher.PublishRecord(key, record)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Small delay to ensure different timestamps
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Wait for all messages
|
||||
messages := collector.WaitForMessages(30 * time.Second)
|
||||
require.Len(t, messages, messageCount)
|
||||
|
||||
// Verify ordering within the partition
|
||||
suite.AssertMessageOrdering(t, messages)
|
||||
}
|
||||
|
||||
func TestSchemaValidation(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
namespace := "test"
|
||||
topicName := "schema-validation"
|
||||
|
||||
// Test with simple schema
|
||||
simpleSchema := CreateTestSchema()
|
||||
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 1,
|
||||
PublisherName: "schema-publisher",
|
||||
RecordType: simpleSchema,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test valid record
|
||||
validRecord := schema.RecordBegin().
|
||||
SetString("id", "valid-msg").
|
||||
SetInt64("timestamp", time.Now().UnixNano()).
|
||||
SetString("content", "Valid message").
|
||||
SetInt32("sequence", 1).
|
||||
RecordEnd()
|
||||
|
||||
err = publisher.PublishRecord([]byte("test-key"), validRecord)
|
||||
assert.NoError(t, err, "Valid record should be published successfully")
|
||||
|
||||
// Test with complex nested schema
|
||||
complexSchema := CreateComplexTestSchema()
|
||||
|
||||
complexPubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName + "-complex",
|
||||
PartitionCount: 1,
|
||||
PublisherName: "complex-publisher",
|
||||
RecordType: complexSchema,
|
||||
}
|
||||
|
||||
complexPublisher, err := suite.CreatePublisher(complexPubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test complex nested record
|
||||
complexRecord := schema.RecordBegin().
|
||||
SetString("user_id", "user123").
|
||||
SetString("name", "John Doe").
|
||||
SetInt32("age", 30).
|
||||
SetStringList("emails", "john@example.com", "john.doe@company.com").
|
||||
SetRecord("address",
|
||||
schema.RecordBegin().
|
||||
SetString("street", "123 Main St").
|
||||
SetString("city", "New York").
|
||||
SetString("zipcode", "10001").
|
||||
RecordEnd()).
|
||||
SetInt64("created_at", time.Now().UnixNano()).
|
||||
RecordEnd()
|
||||
|
||||
err = complexPublisher.PublishRecord([]byte("complex-key"), complexRecord)
|
||||
assert.NoError(t, err, "Complex nested record should be published successfully")
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/agent"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/client/pub_client"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/client/sub_client"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/schema"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
// TestEnvironment holds the configuration for the test environment
|
||||
type TestEnvironment struct {
|
||||
Masters []string
|
||||
Brokers []string
|
||||
Filers []string
|
||||
TestTimeout time.Duration
|
||||
CleanupFuncs []func()
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// IntegrationTestSuite provides the base test framework
|
||||
type IntegrationTestSuite struct {
|
||||
env *TestEnvironment
|
||||
agents map[string]*agent.MessageQueueAgent
|
||||
publishers map[string]*pub_client.TopicPublisher
|
||||
subscribers map[string]*sub_client.TopicSubscriber
|
||||
subCancels map[string]context.CancelFunc
|
||||
cleanupOnce sync.Once
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
// NewIntegrationTestSuite creates a new test suite instance
|
||||
func NewIntegrationTestSuite(t *testing.T) *IntegrationTestSuite {
|
||||
env := &TestEnvironment{
|
||||
Masters: getEnvList("SEAWEED_MASTERS", []string{"localhost:19333"}),
|
||||
Brokers: getEnvList("SEAWEED_BROKERS", []string{"localhost:17777"}),
|
||||
Filers: getEnvList("SEAWEED_FILERS", []string{"localhost:18888"}),
|
||||
TestTimeout: getEnvDuration("GO_TEST_TIMEOUT", 30*time.Minute),
|
||||
}
|
||||
|
||||
return &IntegrationTestSuite{
|
||||
env: env,
|
||||
agents: make(map[string]*agent.MessageQueueAgent),
|
||||
publishers: make(map[string]*pub_client.TopicPublisher),
|
||||
subscribers: make(map[string]*sub_client.TopicSubscriber),
|
||||
subCancels: make(map[string]context.CancelFunc),
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
// Setup initializes the test environment
|
||||
func (its *IntegrationTestSuite) Setup() error {
|
||||
// Wait for cluster to be ready
|
||||
if err := its.waitForClusterReady(); err != nil {
|
||||
return fmt.Errorf("cluster not ready: %v", err)
|
||||
}
|
||||
|
||||
// Register cleanup
|
||||
its.t.Cleanup(its.Cleanup)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup performs cleanup operations
|
||||
func (its *IntegrationTestSuite) Cleanup() {
|
||||
its.cleanupOnce.Do(func() {
|
||||
// Close all subscribers first (they use context cancellation)
|
||||
for name := range its.subscribers {
|
||||
if cancel, ok := its.subCancels[name]; ok && cancel != nil {
|
||||
cancel()
|
||||
its.t.Logf("Cancelled subscriber context: %s", name)
|
||||
}
|
||||
its.t.Logf("Cleaned up subscriber: %s", name)
|
||||
}
|
||||
|
||||
// Wait a moment for gRPC connections to close gracefully
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Close all publishers
|
||||
for name, publisher := range its.publishers {
|
||||
if publisher != nil {
|
||||
// Add timeout to prevent deadlock during shutdown
|
||||
done := make(chan bool, 1)
|
||||
go func(p *pub_client.TopicPublisher, n string) {
|
||||
p.Shutdown()
|
||||
done <- true
|
||||
}(publisher, name)
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
its.t.Logf("Cleaned up publisher: %s", name)
|
||||
case <-time.After(5 * time.Second):
|
||||
its.t.Logf("Publisher shutdown timed out: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute additional cleanup functions
|
||||
its.env.mutex.Lock()
|
||||
for _, cleanup := range its.env.CleanupFuncs {
|
||||
cleanup()
|
||||
}
|
||||
its.env.mutex.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
// CreatePublisher creates a new topic publisher
|
||||
func (its *IntegrationTestSuite) CreatePublisher(config *PublisherTestConfig) (*pub_client.TopicPublisher, error) {
|
||||
publisherConfig := &pub_client.PublisherConfiguration{
|
||||
Topic: topic.NewTopic(config.Namespace, config.TopicName),
|
||||
PartitionCount: config.PartitionCount,
|
||||
Brokers: its.env.Brokers,
|
||||
PublisherName: config.PublisherName,
|
||||
RecordType: config.RecordType,
|
||||
}
|
||||
|
||||
publisher, err := pub_client.NewTopicPublisher(publisherConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create publisher: %v", err)
|
||||
}
|
||||
|
||||
its.publishers[config.PublisherName] = publisher
|
||||
return publisher, nil
|
||||
}
|
||||
|
||||
// CreateSubscriber creates a new topic subscriber
|
||||
func (its *IntegrationTestSuite) CreateSubscriber(config *SubscriberTestConfig) (*sub_client.TopicSubscriber, error) {
|
||||
subscriberConfig := &sub_client.SubscriberConfiguration{
|
||||
ConsumerGroup: config.ConsumerGroup,
|
||||
ConsumerGroupInstanceId: config.ConsumerInstanceId,
|
||||
GrpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
MaxPartitionCount: config.MaxPartitionCount,
|
||||
SlidingWindowSize: config.SlidingWindowSize,
|
||||
}
|
||||
|
||||
contentConfig := &sub_client.ContentConfiguration{
|
||||
Topic: topic.NewTopic(config.Namespace, config.TopicName),
|
||||
Filter: config.Filter,
|
||||
PartitionOffsets: config.PartitionOffsets,
|
||||
OffsetType: config.OffsetType,
|
||||
OffsetTsNs: config.OffsetTsNs,
|
||||
}
|
||||
|
||||
offsetChan := make(chan sub_client.KeyedOffset, 1024)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
subscriber := sub_client.NewTopicSubscriber(
|
||||
ctx,
|
||||
its.env.Brokers,
|
||||
subscriberConfig,
|
||||
contentConfig,
|
||||
offsetChan,
|
||||
)
|
||||
|
||||
its.subscribers[config.ConsumerInstanceId] = subscriber
|
||||
its.subCancels[config.ConsumerInstanceId] = cancel
|
||||
return subscriber, nil
|
||||
}
|
||||
|
||||
// CreateAgent creates a new message queue agent
|
||||
func (its *IntegrationTestSuite) CreateAgent(name string) (*agent.MessageQueueAgent, error) {
|
||||
var brokerAddresses []pb.ServerAddress
|
||||
for _, broker := range its.env.Brokers {
|
||||
brokerAddresses = append(brokerAddresses, pb.ServerAddress(broker))
|
||||
}
|
||||
|
||||
agentOptions := &agent.MessageQueueAgentOptions{
|
||||
SeedBrokers: brokerAddresses,
|
||||
}
|
||||
|
||||
mqAgent := agent.NewMessageQueueAgent(
|
||||
agentOptions,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
|
||||
its.agents[name] = mqAgent
|
||||
return mqAgent, nil
|
||||
}
|
||||
|
||||
// PublisherTestConfig holds configuration for creating test publishers
|
||||
type PublisherTestConfig struct {
|
||||
Namespace string
|
||||
TopicName string
|
||||
PartitionCount int32
|
||||
PublisherName string
|
||||
RecordType *schema_pb.RecordType
|
||||
}
|
||||
|
||||
// SubscriberTestConfig holds configuration for creating test subscribers
|
||||
type SubscriberTestConfig struct {
|
||||
Namespace string
|
||||
TopicName string
|
||||
ConsumerGroup string
|
||||
ConsumerInstanceId string
|
||||
MaxPartitionCount int32
|
||||
SlidingWindowSize int32
|
||||
Filter string
|
||||
PartitionOffsets []*schema_pb.PartitionOffset
|
||||
OffsetType schema_pb.OffsetType
|
||||
OffsetTsNs int64
|
||||
}
|
||||
|
||||
// TestMessage represents a test message with metadata
|
||||
type TestMessage struct {
|
||||
ID string
|
||||
Content []byte
|
||||
Timestamp time.Time
|
||||
Key []byte
|
||||
}
|
||||
|
||||
// MessageCollector collects received messages for verification
|
||||
type MessageCollector struct {
|
||||
messages []TestMessage
|
||||
mutex sync.RWMutex
|
||||
waitCh chan struct{}
|
||||
expected int
|
||||
closed bool // protect against closing waitCh multiple times
|
||||
}
|
||||
|
||||
// NewMessageCollector creates a new message collector
|
||||
func NewMessageCollector(expectedCount int) *MessageCollector {
|
||||
return &MessageCollector{
|
||||
messages: make([]TestMessage, 0),
|
||||
waitCh: make(chan struct{}),
|
||||
expected: expectedCount,
|
||||
}
|
||||
}
|
||||
|
||||
// AddMessage adds a received message to the collector
|
||||
func (mc *MessageCollector) AddMessage(msg TestMessage) {
|
||||
mc.mutex.Lock()
|
||||
defer mc.mutex.Unlock()
|
||||
|
||||
mc.messages = append(mc.messages, msg)
|
||||
if len(mc.messages) >= mc.expected && !mc.closed {
|
||||
close(mc.waitCh)
|
||||
mc.closed = true
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForMessages waits for the expected number of messages or timeout
|
||||
func (mc *MessageCollector) WaitForMessages(timeout time.Duration) []TestMessage {
|
||||
select {
|
||||
case <-mc.waitCh:
|
||||
case <-time.After(timeout):
|
||||
}
|
||||
|
||||
mc.mutex.RLock()
|
||||
defer mc.mutex.RUnlock()
|
||||
|
||||
result := make([]TestMessage, len(mc.messages))
|
||||
copy(result, mc.messages)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetMessages returns all collected messages
|
||||
func (mc *MessageCollector) GetMessages() []TestMessage {
|
||||
mc.mutex.RLock()
|
||||
defer mc.mutex.RUnlock()
|
||||
|
||||
result := make([]TestMessage, len(mc.messages))
|
||||
copy(result, mc.messages)
|
||||
return result
|
||||
}
|
||||
|
||||
// CreateTestSchema creates a simple test schema
|
||||
func CreateTestSchema() *schema_pb.RecordType {
|
||||
return schema.RecordTypeBegin().
|
||||
WithField("id", schema.TypeString).
|
||||
WithField("timestamp", schema.TypeInt64).
|
||||
WithField("content", schema.TypeString).
|
||||
WithField("sequence", schema.TypeInt32).
|
||||
RecordTypeEnd()
|
||||
}
|
||||
|
||||
// CreateComplexTestSchema creates a complex test schema with nested structures
|
||||
func CreateComplexTestSchema() *schema_pb.RecordType {
|
||||
addressType := schema.RecordTypeBegin().
|
||||
WithField("street", schema.TypeString).
|
||||
WithField("city", schema.TypeString).
|
||||
WithField("zipcode", schema.TypeString).
|
||||
RecordTypeEnd()
|
||||
|
||||
return schema.RecordTypeBegin().
|
||||
WithField("user_id", schema.TypeString).
|
||||
WithField("name", schema.TypeString).
|
||||
WithField("age", schema.TypeInt32).
|
||||
WithField("emails", schema.ListOf(schema.TypeString)).
|
||||
WithRecordField("address", addressType).
|
||||
WithField("created_at", schema.TypeInt64).
|
||||
RecordTypeEnd()
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
func getEnvList(key string, defaultValue []string) []string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return strings.Split(value, ",")
|
||||
}
|
||||
|
||||
func getEnvDuration(key string, defaultValue time.Duration) time.Duration {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
func (its *IntegrationTestSuite) waitForClusterReady() error {
|
||||
maxRetries := 30
|
||||
retryInterval := 2 * time.Second
|
||||
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
if its.isClusterReady() {
|
||||
return nil
|
||||
}
|
||||
its.t.Logf("Waiting for cluster to be ready... attempt %d/%d", i+1, maxRetries)
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
|
||||
return fmt.Errorf("cluster not ready after %d attempts", maxRetries)
|
||||
}
|
||||
|
||||
func (its *IntegrationTestSuite) isClusterReady() bool {
|
||||
// Check if at least one broker is accessible
|
||||
for _, broker := range its.env.Brokers {
|
||||
if its.isBrokerReady(broker) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (its *IntegrationTestSuite) isBrokerReady(broker string) bool {
|
||||
// Simple connection test
|
||||
conn, err := grpc.NewClient(broker, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// TODO: Add actual health check call here
|
||||
return true
|
||||
}
|
||||
|
||||
// AssertMessagesReceived verifies that expected messages were received
|
||||
func (its *IntegrationTestSuite) AssertMessagesReceived(t *testing.T, collector *MessageCollector, expectedCount int, timeout time.Duration) {
|
||||
messages := collector.WaitForMessages(timeout)
|
||||
require.Len(t, messages, expectedCount, "Expected %d messages, got %d", expectedCount, len(messages))
|
||||
}
|
||||
|
||||
// AssertMessageOrdering verifies that messages are received in the expected order
|
||||
func (its *IntegrationTestSuite) AssertMessageOrdering(t *testing.T, messages []TestMessage) {
|
||||
for i := 1; i < len(messages); i++ {
|
||||
require.True(t, messages[i].Timestamp.After(messages[i-1].Timestamp) || messages[i].Timestamp.Equal(messages[i-1].Timestamp),
|
||||
"Messages not in chronological order: message %d timestamp %v should be >= message %d timestamp %v",
|
||||
i, messages[i].Timestamp, i-1, messages[i-1].Timestamp)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,666 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// PerformanceMetrics holds test metrics
|
||||
type PerformanceMetrics struct {
|
||||
MessagesPublished int64
|
||||
MessagesConsumed int64
|
||||
PublishLatencies []time.Duration
|
||||
ConsumeLatencies []time.Duration
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
ErrorCount int64
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (m *PerformanceMetrics) AddPublishLatency(d time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.PublishLatencies = append(m.PublishLatencies, d)
|
||||
}
|
||||
|
||||
func (m *PerformanceMetrics) AddConsumeLatency(d time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.ConsumeLatencies = append(m.ConsumeLatencies, d)
|
||||
}
|
||||
|
||||
func (m *PerformanceMetrics) GetThroughput() float64 {
|
||||
duration := m.EndTime.Sub(m.StartTime).Seconds()
|
||||
if duration == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(atomic.LoadInt64(&m.MessagesPublished)) / duration
|
||||
}
|
||||
|
||||
func (m *PerformanceMetrics) GetP95Latency(latencies []time.Duration) time.Duration {
|
||||
if len(latencies) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Simple P95 calculation - in production use proper percentile library
|
||||
index := int(float64(len(latencies)) * 0.95)
|
||||
if index >= len(latencies) {
|
||||
index = len(latencies) - 1
|
||||
}
|
||||
|
||||
// Sort latencies (simplified)
|
||||
for i := 0; i < len(latencies)-1; i++ {
|
||||
for j := 0; j < len(latencies)-i-1; j++ {
|
||||
if latencies[j] > latencies[j+1] {
|
||||
latencies[j], latencies[j+1] = latencies[j+1], latencies[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return latencies[index]
|
||||
}
|
||||
|
||||
// Enhanced performance metrics with connection error tracking
|
||||
type EnhancedPerformanceMetrics struct {
|
||||
MessagesPublished int64
|
||||
MessagesConsumed int64
|
||||
PublishLatencies []time.Duration
|
||||
ConsumeLatencies []time.Duration
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
ErrorCount int64
|
||||
ConnectionErrors int64
|
||||
ApplicationErrors int64
|
||||
RetryAttempts int64
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (m *EnhancedPerformanceMetrics) AddPublishLatency(d time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.PublishLatencies = append(m.PublishLatencies, d)
|
||||
}
|
||||
|
||||
func (m *EnhancedPerformanceMetrics) AddConsumeLatency(d time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.ConsumeLatencies = append(m.ConsumeLatencies, d)
|
||||
}
|
||||
|
||||
func (m *EnhancedPerformanceMetrics) GetThroughput() float64 {
|
||||
duration := m.EndTime.Sub(m.StartTime).Seconds()
|
||||
if duration == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(atomic.LoadInt64(&m.MessagesPublished)) / duration
|
||||
}
|
||||
|
||||
func (m *EnhancedPerformanceMetrics) GetP95Latency(latencies []time.Duration) time.Duration {
|
||||
if len(latencies) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Simple P95 calculation
|
||||
index := int(float64(len(latencies)) * 0.95)
|
||||
if index >= len(latencies) {
|
||||
index = len(latencies) - 1
|
||||
}
|
||||
|
||||
// Sort latencies (simplified bubble sort for small datasets)
|
||||
sorted := make([]time.Duration, len(latencies))
|
||||
copy(sorted, latencies)
|
||||
for i := 0; i < len(sorted)-1; i++ {
|
||||
for j := 0; j < len(sorted)-i-1; j++ {
|
||||
if sorted[j] > sorted[j+1] {
|
||||
sorted[j], sorted[j+1] = sorted[j+1], sorted[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sorted[index]
|
||||
}
|
||||
|
||||
// isConnectionError determines if an error is a connection-level error
|
||||
func isConnectionError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
errStr := err.Error()
|
||||
|
||||
// Check for gRPC status codes
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled, codes.Unknown:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common connection error strings
|
||||
connectionErrorPatterns := []string{
|
||||
"EOF",
|
||||
"error reading server preface",
|
||||
"connection refused",
|
||||
"connection reset",
|
||||
"broken pipe",
|
||||
"network is unreachable",
|
||||
"no route to host",
|
||||
"transport is closing",
|
||||
"connection error",
|
||||
"dial tcp",
|
||||
"context deadline exceeded",
|
||||
}
|
||||
|
||||
for _, pattern := range connectionErrorPatterns {
|
||||
if containsString(errStr, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func containsString(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestPerformanceThroughput(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
topicName := "performance-throughput-test"
|
||||
namespace := "perf-test"
|
||||
|
||||
metrics := &PerformanceMetrics{
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
// Test parameters
|
||||
numMessages := 50000
|
||||
numPublishers := 5
|
||||
messageSize := 1024 // 1KB messages
|
||||
|
||||
// Create message payload
|
||||
payload := make([]byte, messageSize)
|
||||
for i := range payload {
|
||||
payload[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
t.Logf("Starting throughput test: %d messages, %d publishers, %d bytes per message",
|
||||
numMessages, numPublishers, messageSize)
|
||||
|
||||
// Start publishers
|
||||
var publishWg sync.WaitGroup
|
||||
messagesPerPublisher := numMessages / numPublishers
|
||||
|
||||
for i := 0; i < numPublishers; i++ {
|
||||
publishWg.Add(1)
|
||||
go func(publisherID int) {
|
||||
defer publishWg.Done()
|
||||
|
||||
// Create publisher for this goroutine
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 4, // Multiple partitions for better throughput
|
||||
PublisherName: fmt.Sprintf("perf-publisher-%d", publisherID),
|
||||
RecordType: nil, // Use raw publish
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.ErrorCount, 1)
|
||||
t.Errorf("Failed to create publisher %d: %v", publisherID, err)
|
||||
return
|
||||
}
|
||||
|
||||
for j := 0; j < messagesPerPublisher; j++ {
|
||||
messageKey := fmt.Sprintf("publisher-%d-msg-%d", publisherID, j)
|
||||
|
||||
start := time.Now()
|
||||
err := publisher.Publish([]byte(messageKey), payload)
|
||||
latency := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.ErrorCount, 1)
|
||||
continue
|
||||
}
|
||||
|
||||
atomic.AddInt64(&metrics.MessagesPublished, 1)
|
||||
metrics.AddPublishLatency(latency)
|
||||
|
||||
// Small delay to prevent overwhelming the system
|
||||
if j%1000 == 0 {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Wait for publishing to complete
|
||||
publishWg.Wait()
|
||||
metrics.EndTime = time.Now()
|
||||
|
||||
// Verify results
|
||||
publishedCount := atomic.LoadInt64(&metrics.MessagesPublished)
|
||||
errorCount := atomic.LoadInt64(&metrics.ErrorCount)
|
||||
throughput := metrics.GetThroughput()
|
||||
|
||||
t.Logf("Performance Results:")
|
||||
t.Logf(" Messages Published: %d", publishedCount)
|
||||
t.Logf(" Errors: %d", errorCount)
|
||||
t.Logf(" Throughput: %.2f messages/second", throughput)
|
||||
t.Logf(" Duration: %v", metrics.EndTime.Sub(metrics.StartTime))
|
||||
|
||||
if len(metrics.PublishLatencies) > 0 {
|
||||
p95Latency := metrics.GetP95Latency(metrics.PublishLatencies)
|
||||
t.Logf(" P95 Publish Latency: %v", p95Latency)
|
||||
|
||||
// Performance assertions
|
||||
assert.Less(t, p95Latency, 100*time.Millisecond, "P95 publish latency should be under 100ms")
|
||||
}
|
||||
|
||||
// Throughput requirements
|
||||
expectedMinThroughput := 5000.0 // 5K messages/sec minimum (relaxed from 10K for initial testing)
|
||||
assert.Greater(t, throughput, expectedMinThroughput,
|
||||
"Throughput should exceed %.0f messages/second", expectedMinThroughput)
|
||||
|
||||
// Error rate should be low
|
||||
errorRate := float64(errorCount) / float64(publishedCount+errorCount)
|
||||
assert.Less(t, errorRate, 0.05, "Error rate should be less than 5%")
|
||||
}
|
||||
|
||||
func TestPerformanceLatency(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
topicName := "performance-latency-test"
|
||||
namespace := "perf-test"
|
||||
|
||||
// Create publisher
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 1, // Single partition for latency testing
|
||||
PublisherName: "latency-publisher",
|
||||
RecordType: nil,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start consumer first
|
||||
subConfig := &SubscriberTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
ConsumerGroup: "latency-test-group",
|
||||
ConsumerInstanceId: "latency-consumer-1",
|
||||
MaxPartitionCount: 1,
|
||||
SlidingWindowSize: 10,
|
||||
OffsetType: schema_pb.OffsetType_RESET_TO_EARLIEST,
|
||||
}
|
||||
|
||||
subscriber, err := suite.CreateSubscriber(subConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
numMessages := 5000
|
||||
collector := NewMessageCollector(numMessages)
|
||||
|
||||
// Set up message handler
|
||||
subscriber.SetOnDataMessageFn(func(m *mq_pb.SubscribeMessageResponse_Data) {
|
||||
collector.AddMessage(TestMessage{
|
||||
ID: string(m.Data.Key),
|
||||
Content: m.Data.Value,
|
||||
Timestamp: time.Unix(0, m.Data.TsNs),
|
||||
Key: m.Data.Key,
|
||||
})
|
||||
})
|
||||
|
||||
// Start subscriber
|
||||
go func() {
|
||||
err := subscriber.Subscribe()
|
||||
if err != nil {
|
||||
t.Logf("Subscriber error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for consumer to be ready
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
metrics := &PerformanceMetrics{
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
t.Logf("Starting latency test with %d messages", numMessages)
|
||||
|
||||
// Publish messages with controlled timing
|
||||
for i := 0; i < numMessages; i++ {
|
||||
messageKey := fmt.Sprintf("latency-msg-%d", i)
|
||||
payload := fmt.Sprintf("test-payload-data-%d", i)
|
||||
|
||||
start := time.Now()
|
||||
err := publisher.Publish([]byte(messageKey), []byte(payload))
|
||||
publishLatency := time.Since(start)
|
||||
|
||||
require.NoError(t, err)
|
||||
metrics.AddPublishLatency(publishLatency)
|
||||
|
||||
// Controlled rate for latency measurement
|
||||
if i%100 == 0 {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
metrics.EndTime = time.Now()
|
||||
|
||||
// Wait for messages to be consumed
|
||||
messages := collector.WaitForMessages(30 * time.Second)
|
||||
|
||||
// Analyze latency results
|
||||
t.Logf("Latency Test Results:")
|
||||
t.Logf(" Messages Published: %d", numMessages)
|
||||
t.Logf(" Messages Consumed: %d", len(messages))
|
||||
|
||||
if len(metrics.PublishLatencies) > 0 {
|
||||
p95PublishLatency := metrics.GetP95Latency(metrics.PublishLatencies)
|
||||
t.Logf(" P95 Publish Latency: %v", p95PublishLatency)
|
||||
|
||||
// Latency assertions
|
||||
assert.Less(t, p95PublishLatency, 50*time.Millisecond,
|
||||
"P95 publish latency should be under 50ms")
|
||||
}
|
||||
|
||||
// Verify message delivery
|
||||
deliveryRate := float64(len(messages)) / float64(numMessages)
|
||||
assert.Greater(t, deliveryRate, 0.80, "Should deliver at least 80% of messages")
|
||||
}
|
||||
|
||||
func TestPerformanceConcurrentConsumers(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
topicName := "performance-concurrent-test"
|
||||
namespace := "perf-test"
|
||||
numPartitions := int32(4)
|
||||
|
||||
// Create publisher first
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: numPartitions,
|
||||
PublisherName: "concurrent-publisher",
|
||||
RecordType: nil,
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test parameters
|
||||
numConsumers := 8
|
||||
numMessages := 20000
|
||||
consumerGroup := "concurrent-perf-group"
|
||||
|
||||
t.Logf("Starting concurrent consumer test: %d consumers, %d messages, %d partitions",
|
||||
numConsumers, numMessages, numPartitions)
|
||||
|
||||
// Start multiple consumers
|
||||
var collectors []*MessageCollector
|
||||
|
||||
for i := 0; i < numConsumers; i++ {
|
||||
collector := NewMessageCollector(numMessages / numConsumers) // Expected per consumer
|
||||
collectors = append(collectors, collector)
|
||||
|
||||
subConfig := &SubscriberTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
ConsumerGroup: consumerGroup,
|
||||
ConsumerInstanceId: fmt.Sprintf("consumer-%d", i),
|
||||
MaxPartitionCount: numPartitions,
|
||||
SlidingWindowSize: 10,
|
||||
OffsetType: schema_pb.OffsetType_RESET_TO_EARLIEST,
|
||||
}
|
||||
|
||||
subscriber, err := suite.CreateSubscriber(subConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up message handler for this consumer
|
||||
func(consumerID int, c *MessageCollector) {
|
||||
subscriber.SetOnDataMessageFn(func(m *mq_pb.SubscribeMessageResponse_Data) {
|
||||
c.AddMessage(TestMessage{
|
||||
ID: fmt.Sprintf("%d-%s", consumerID, string(m.Data.Key)),
|
||||
Content: m.Data.Value,
|
||||
Timestamp: time.Unix(0, m.Data.TsNs),
|
||||
Key: m.Data.Key,
|
||||
})
|
||||
})
|
||||
}(i, collector)
|
||||
|
||||
// Start subscriber
|
||||
go func(consumerID int, s *SubscriberTestConfig) {
|
||||
sub, _ := suite.CreateSubscriber(s)
|
||||
err := sub.Subscribe()
|
||||
if err != nil {
|
||||
t.Logf("Consumer %d error: %v", consumerID, err)
|
||||
}
|
||||
}(i, subConfig)
|
||||
}
|
||||
|
||||
// Wait for consumers to initialize
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Start publishing
|
||||
startTime := time.Now()
|
||||
|
||||
var publishWg sync.WaitGroup
|
||||
numPublishers := 3
|
||||
messagesPerPublisher := numMessages / numPublishers
|
||||
|
||||
for i := 0; i < numPublishers; i++ {
|
||||
publishWg.Add(1)
|
||||
go func(publisherID int) {
|
||||
defer publishWg.Done()
|
||||
|
||||
for j := 0; j < messagesPerPublisher; j++ {
|
||||
messageKey := fmt.Sprintf("concurrent-msg-%d-%d", publisherID, j)
|
||||
payload := fmt.Sprintf("publisher-%d-message-%d-data", publisherID, j)
|
||||
|
||||
err := publisher.Publish([]byte(messageKey), []byte(payload))
|
||||
|
||||
if err != nil {
|
||||
t.Logf("Publish error: %v", err)
|
||||
}
|
||||
|
||||
// Rate limiting
|
||||
if j%1000 == 0 {
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
publishWg.Wait()
|
||||
publishDuration := time.Since(startTime)
|
||||
|
||||
// Allow time for message consumption
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
// Analyze results
|
||||
totalConsumed := int64(0)
|
||||
for i, collector := range collectors {
|
||||
messages := collector.GetMessages()
|
||||
consumed := int64(len(messages))
|
||||
totalConsumed += consumed
|
||||
t.Logf("Consumer %d consumed %d messages", i, consumed)
|
||||
}
|
||||
|
||||
publishThroughput := float64(numMessages) / publishDuration.Seconds()
|
||||
consumeThroughput := float64(totalConsumed) / publishDuration.Seconds()
|
||||
|
||||
t.Logf("Concurrent Consumer Test Results:")
|
||||
t.Logf(" Total Published: %d", numMessages)
|
||||
t.Logf(" Total Consumed: %d", totalConsumed)
|
||||
t.Logf(" Publish Throughput: %.2f msg/sec", publishThroughput)
|
||||
t.Logf(" Consume Throughput: %.2f msg/sec", consumeThroughput)
|
||||
t.Logf(" Test Duration: %v", publishDuration)
|
||||
|
||||
// Performance assertions (relaxed for initial testing)
|
||||
deliveryRate := float64(totalConsumed) / float64(numMessages)
|
||||
assert.Greater(t, deliveryRate, 0.70, "Should consume at least 70% of messages")
|
||||
|
||||
expectedMinThroughput := 2000.0 // 2K messages/sec minimum for concurrent consumption
|
||||
assert.Greater(t, consumeThroughput, expectedMinThroughput,
|
||||
"Consume throughput should exceed %.0f messages/second", expectedMinThroughput)
|
||||
}
|
||||
|
||||
func TestPerformanceWithErrorHandling(t *testing.T) {
|
||||
suite := NewIntegrationTestSuite(t)
|
||||
require.NoError(t, suite.Setup())
|
||||
|
||||
topicName := "performance-error-handling-test"
|
||||
namespace := "perf-test"
|
||||
|
||||
metrics := &EnhancedPerformanceMetrics{
|
||||
StartTime: time.Now(),
|
||||
}
|
||||
|
||||
// Test parameters
|
||||
numMessages := 50000
|
||||
numPublishers := 5
|
||||
messageSize := 1024 // 1KB messages
|
||||
|
||||
// Create message payload
|
||||
payload := make([]byte, messageSize)
|
||||
for i := range payload {
|
||||
payload[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
t.Logf("Starting performance test with enhanced error handling: %d messages, %d publishers, %d bytes per message",
|
||||
numMessages, numPublishers, messageSize)
|
||||
|
||||
// Start publishers
|
||||
var publishWg sync.WaitGroup
|
||||
messagesPerPublisher := numMessages / numPublishers
|
||||
|
||||
for i := 0; i < numPublishers; i++ {
|
||||
publishWg.Add(1)
|
||||
go func(publisherID int) {
|
||||
defer publishWg.Done()
|
||||
|
||||
// Create publisher for this goroutine
|
||||
pubConfig := &PublisherTestConfig{
|
||||
Namespace: namespace,
|
||||
TopicName: topicName,
|
||||
PartitionCount: 4, // Multiple partitions for better throughput
|
||||
PublisherName: fmt.Sprintf("error-aware-publisher-%d", publisherID),
|
||||
RecordType: nil, // Use raw publish
|
||||
}
|
||||
|
||||
publisher, err := suite.CreatePublisher(pubConfig)
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.ErrorCount, 1)
|
||||
t.Errorf("Failed to create publisher %d: %v", publisherID, err)
|
||||
return
|
||||
}
|
||||
|
||||
for j := 0; j < messagesPerPublisher; j++ {
|
||||
messageKey := fmt.Sprintf("publisher-%d-msg-%d", publisherID, j)
|
||||
|
||||
start := time.Now()
|
||||
err := publisher.Publish([]byte(messageKey), payload)
|
||||
latency := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
atomic.AddInt64(&metrics.ErrorCount, 1)
|
||||
|
||||
// Classify the error type
|
||||
if isConnectionError(err) {
|
||||
atomic.AddInt64(&metrics.ConnectionErrors, 1)
|
||||
t.Logf("Connection error (publisher %d, msg %d): %v", publisherID, j, err)
|
||||
} else {
|
||||
atomic.AddInt64(&metrics.ApplicationErrors, 1)
|
||||
t.Logf("Application error (publisher %d, msg %d): %v", publisherID, j, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
atomic.AddInt64(&metrics.MessagesPublished, 1)
|
||||
metrics.AddPublishLatency(latency)
|
||||
|
||||
// Small delay to prevent overwhelming the system
|
||||
if j%1000 == 0 {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Wait for publishing to complete
|
||||
publishWg.Wait()
|
||||
metrics.EndTime = time.Now()
|
||||
|
||||
// Analyze results with enhanced error reporting
|
||||
publishedCount := atomic.LoadInt64(&metrics.MessagesPublished)
|
||||
totalErrors := atomic.LoadInt64(&metrics.ErrorCount)
|
||||
connectionErrors := atomic.LoadInt64(&metrics.ConnectionErrors)
|
||||
applicationErrors := atomic.LoadInt64(&metrics.ApplicationErrors)
|
||||
throughput := metrics.GetThroughput()
|
||||
|
||||
t.Logf("Enhanced Performance Results:")
|
||||
t.Logf(" Messages Successfully Published: %d", publishedCount)
|
||||
t.Logf(" Total Errors: %d", totalErrors)
|
||||
t.Logf(" Connection-Level Errors: %d", connectionErrors)
|
||||
t.Logf(" Application-Level Errors: %d", applicationErrors)
|
||||
t.Logf(" Throughput: %.2f messages/second", throughput)
|
||||
t.Logf(" Duration: %v", metrics.EndTime.Sub(metrics.StartTime))
|
||||
|
||||
if len(metrics.PublishLatencies) > 0 {
|
||||
p95Latency := metrics.GetP95Latency(metrics.PublishLatencies)
|
||||
t.Logf(" P95 Publish Latency: %v", p95Latency)
|
||||
|
||||
// Performance assertions (adjusted for error handling overhead)
|
||||
assert.Less(t, p95Latency, 100*time.Millisecond, "P95 publish latency should be under 100ms")
|
||||
}
|
||||
|
||||
// Enhanced error analysis
|
||||
totalAttempts := publishedCount + totalErrors
|
||||
if totalAttempts > 0 {
|
||||
successRate := float64(publishedCount) / float64(totalAttempts)
|
||||
connectionErrorRate := float64(connectionErrors) / float64(totalAttempts)
|
||||
applicationErrorRate := float64(applicationErrors) / float64(totalAttempts)
|
||||
|
||||
t.Logf("Error Analysis:")
|
||||
t.Logf(" Success Rate: %.2f%%", successRate*100)
|
||||
t.Logf(" Connection Error Rate: %.2f%%", connectionErrorRate*100)
|
||||
t.Logf(" Application Error Rate: %.2f%%", applicationErrorRate*100)
|
||||
|
||||
// Assertions based on error types
|
||||
assert.Greater(t, successRate, 0.80, "Success rate should be greater than 80%")
|
||||
assert.Less(t, applicationErrorRate, 0.01, "Application error rate should be less than 1%")
|
||||
|
||||
// Connection errors are expected under high load but should be handled
|
||||
if connectionErrors > 0 {
|
||||
t.Logf("Note: %d connection errors detected - this indicates the test is successfully stressing the system", connectionErrors)
|
||||
t.Logf("Recommendation: Implement retry logic for production applications to handle these connection errors")
|
||||
}
|
||||
}
|
||||
|
||||
// Throughput requirements (adjusted for error handling)
|
||||
expectedMinThroughput := 5000.0 // 5K messages/sec minimum
|
||||
assert.Greater(t, throughput, expectedMinThroughput,
|
||||
"Throughput should exceed %.0f messages/second", expectedMinThroughput)
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/client/pub_client"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// ResilientPublisher wraps TopicPublisher with enhanced error handling
|
||||
type ResilientPublisher struct {
|
||||
publisher *pub_client.TopicPublisher
|
||||
config *PublisherTestConfig
|
||||
suite *IntegrationTestSuite
|
||||
|
||||
// Error tracking
|
||||
connectionErrors int64
|
||||
applicationErrors int64
|
||||
retryAttempts int64
|
||||
totalPublishes int64
|
||||
|
||||
// Retry configuration
|
||||
maxRetries int
|
||||
baseDelay time.Duration
|
||||
maxDelay time.Duration
|
||||
backoffFactor float64
|
||||
|
||||
// Circuit breaker
|
||||
circuitOpen bool
|
||||
circuitOpenTime time.Time
|
||||
circuitTimeout time.Duration
|
||||
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// RetryConfig holds retry configuration
|
||||
type RetryConfig struct {
|
||||
MaxRetries int
|
||||
BaseDelay time.Duration
|
||||
MaxDelay time.Duration
|
||||
BackoffFactor float64
|
||||
CircuitTimeout time.Duration
|
||||
}
|
||||
|
||||
// DefaultRetryConfig returns sensible defaults for retry configuration
|
||||
func DefaultRetryConfig() *RetryConfig {
|
||||
return &RetryConfig{
|
||||
MaxRetries: 5,
|
||||
BaseDelay: 10 * time.Millisecond,
|
||||
MaxDelay: 5 * time.Second,
|
||||
BackoffFactor: 2.0,
|
||||
CircuitTimeout: 30 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// NewResilientPublisher creates a new resilient publisher
|
||||
func (its *IntegrationTestSuite) CreateResilientPublisher(config *PublisherTestConfig, retryConfig *RetryConfig) (*ResilientPublisher, error) {
|
||||
if retryConfig == nil {
|
||||
retryConfig = DefaultRetryConfig()
|
||||
}
|
||||
|
||||
publisher, err := its.CreatePublisher(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create base publisher: %v", err)
|
||||
}
|
||||
|
||||
return &ResilientPublisher{
|
||||
publisher: publisher,
|
||||
config: config,
|
||||
suite: its,
|
||||
maxRetries: retryConfig.MaxRetries,
|
||||
baseDelay: retryConfig.BaseDelay,
|
||||
maxDelay: retryConfig.MaxDelay,
|
||||
backoffFactor: retryConfig.BackoffFactor,
|
||||
circuitTimeout: retryConfig.CircuitTimeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PublishWithRetry publishes a message with retry logic and error handling
|
||||
func (rp *ResilientPublisher) PublishWithRetry(key, value []byte) error {
|
||||
atomic.AddInt64(&rp.totalPublishes, 1)
|
||||
|
||||
// Check circuit breaker
|
||||
if rp.isCircuitOpen() {
|
||||
atomic.AddInt64(&rp.applicationErrors, 1)
|
||||
return fmt.Errorf("circuit breaker is open")
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= rp.maxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
atomic.AddInt64(&rp.retryAttempts, 1)
|
||||
delay := rp.calculateDelay(attempt)
|
||||
glog.V(1).Infof("Retrying publish after %v (attempt %d/%d)", delay, attempt, rp.maxRetries)
|
||||
time.Sleep(delay)
|
||||
}
|
||||
|
||||
err := rp.publisher.Publish(key, value)
|
||||
if err == nil {
|
||||
// Success - reset circuit breaker if it was open
|
||||
rp.resetCircuitBreaker()
|
||||
return nil
|
||||
}
|
||||
|
||||
lastErr = err
|
||||
|
||||
// Classify error type
|
||||
if rp.isConnectionError(err) {
|
||||
atomic.AddInt64(&rp.connectionErrors, 1)
|
||||
glog.V(1).Infof("Connection error on attempt %d: %v", attempt+1, err)
|
||||
|
||||
// For connection errors, try to recreate the publisher
|
||||
if attempt < rp.maxRetries {
|
||||
if recreateErr := rp.recreatePublisher(); recreateErr != nil {
|
||||
glog.Warningf("Failed to recreate publisher: %v", recreateErr)
|
||||
}
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
// Application error - don't retry
|
||||
atomic.AddInt64(&rp.applicationErrors, 1)
|
||||
glog.Warningf("Application error (not retrying): %v", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// All retries exhausted or non-retryable error
|
||||
rp.openCircuitBreaker()
|
||||
return fmt.Errorf("publish failed after %d attempts, last error: %v", rp.maxRetries+1, lastErr)
|
||||
}
|
||||
|
||||
// PublishRecord publishes a record with retry logic
|
||||
func (rp *ResilientPublisher) PublishRecord(key []byte, record *schema_pb.RecordValue) error {
|
||||
atomic.AddInt64(&rp.totalPublishes, 1)
|
||||
|
||||
if rp.isCircuitOpen() {
|
||||
atomic.AddInt64(&rp.applicationErrors, 1)
|
||||
return fmt.Errorf("circuit breaker is open")
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
for attempt := 0; attempt <= rp.maxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
atomic.AddInt64(&rp.retryAttempts, 1)
|
||||
delay := rp.calculateDelay(attempt)
|
||||
time.Sleep(delay)
|
||||
}
|
||||
|
||||
err := rp.publisher.PublishRecord(key, record)
|
||||
if err == nil {
|
||||
rp.resetCircuitBreaker()
|
||||
return nil
|
||||
}
|
||||
|
||||
lastErr = err
|
||||
|
||||
if rp.isConnectionError(err) {
|
||||
atomic.AddInt64(&rp.connectionErrors, 1)
|
||||
if attempt < rp.maxRetries {
|
||||
if recreateErr := rp.recreatePublisher(); recreateErr != nil {
|
||||
glog.Warningf("Failed to recreate publisher: %v", recreateErr)
|
||||
}
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
atomic.AddInt64(&rp.applicationErrors, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
rp.openCircuitBreaker()
|
||||
return fmt.Errorf("publish record failed after %d attempts, last error: %v", rp.maxRetries+1, lastErr)
|
||||
}
|
||||
|
||||
// recreatePublisher attempts to recreate the underlying publisher
|
||||
func (rp *ResilientPublisher) recreatePublisher() error {
|
||||
rp.mu.Lock()
|
||||
defer rp.mu.Unlock()
|
||||
|
||||
// Shutdown old publisher
|
||||
if rp.publisher != nil {
|
||||
rp.publisher.Shutdown()
|
||||
}
|
||||
|
||||
// Create new publisher
|
||||
newPublisher, err := rp.suite.CreatePublisher(rp.config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to recreate publisher: %v", err)
|
||||
}
|
||||
|
||||
rp.publisher = newPublisher
|
||||
glog.V(1).Infof("Successfully recreated publisher")
|
||||
return nil
|
||||
}
|
||||
|
||||
// isConnectionError determines if an error is a connection-level error that should be retried
|
||||
func (rp *ResilientPublisher) isConnectionError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
errStr := err.Error()
|
||||
|
||||
// Check for gRPC status codes
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled, codes.Unknown:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common connection error strings
|
||||
connectionErrorPatterns := []string{
|
||||
"EOF",
|
||||
"error reading server preface",
|
||||
"connection refused",
|
||||
"connection reset",
|
||||
"broken pipe",
|
||||
"network is unreachable",
|
||||
"no route to host",
|
||||
"transport is closing",
|
||||
"connection error",
|
||||
"dial tcp",
|
||||
"context deadline exceeded",
|
||||
}
|
||||
|
||||
for _, pattern := range connectionErrorPatterns {
|
||||
if contains(errStr, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// contains checks if a string contains a substring (case-insensitive)
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) &&
|
||||
(s == substr ||
|
||||
len(s) > len(substr) &&
|
||||
(s[:len(substr)] == substr ||
|
||||
s[len(s)-len(substr):] == substr ||
|
||||
containsSubstring(s, substr)))
|
||||
}
|
||||
|
||||
func containsSubstring(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// calculateDelay calculates exponential backoff delay
|
||||
func (rp *ResilientPublisher) calculateDelay(attempt int) time.Duration {
|
||||
delay := float64(rp.baseDelay) * math.Pow(rp.backoffFactor, float64(attempt-1))
|
||||
if delay > float64(rp.maxDelay) {
|
||||
delay = float64(rp.maxDelay)
|
||||
}
|
||||
return time.Duration(delay)
|
||||
}
|
||||
|
||||
// Circuit breaker methods
|
||||
func (rp *ResilientPublisher) isCircuitOpen() bool {
|
||||
rp.mu.RLock()
|
||||
defer rp.mu.RUnlock()
|
||||
|
||||
if !rp.circuitOpen {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if circuit should be reset
|
||||
if time.Since(rp.circuitOpenTime) > rp.circuitTimeout {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (rp *ResilientPublisher) openCircuitBreaker() {
|
||||
rp.mu.Lock()
|
||||
defer rp.mu.Unlock()
|
||||
|
||||
rp.circuitOpen = true
|
||||
rp.circuitOpenTime = time.Now()
|
||||
glog.Warningf("Circuit breaker opened due to repeated failures")
|
||||
}
|
||||
|
||||
func (rp *ResilientPublisher) resetCircuitBreaker() {
|
||||
rp.mu.Lock()
|
||||
defer rp.mu.Unlock()
|
||||
|
||||
if rp.circuitOpen {
|
||||
rp.circuitOpen = false
|
||||
glog.V(1).Infof("Circuit breaker reset")
|
||||
}
|
||||
}
|
||||
|
||||
// GetErrorStats returns error statistics
|
||||
func (rp *ResilientPublisher) GetErrorStats() ErrorStats {
|
||||
return ErrorStats{
|
||||
ConnectionErrors: atomic.LoadInt64(&rp.connectionErrors),
|
||||
ApplicationErrors: atomic.LoadInt64(&rp.applicationErrors),
|
||||
RetryAttempts: atomic.LoadInt64(&rp.retryAttempts),
|
||||
TotalPublishes: atomic.LoadInt64(&rp.totalPublishes),
|
||||
CircuitOpen: rp.isCircuitOpen(),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorStats holds error statistics
|
||||
type ErrorStats struct {
|
||||
ConnectionErrors int64
|
||||
ApplicationErrors int64
|
||||
RetryAttempts int64
|
||||
TotalPublishes int64
|
||||
CircuitOpen bool
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down the resilient publisher
|
||||
func (rp *ResilientPublisher) Shutdown() error {
|
||||
rp.mu.Lock()
|
||||
defer rp.mu.Unlock()
|
||||
|
||||
if rp.publisher != nil {
|
||||
return rp.publisher.Shutdown()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
# SeaweedMQ Integration Test Design
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the comprehensive integration test strategy for SeaweedMQ, covering all critical functionalities from basic pub/sub operations to advanced features like auto-scaling, failover, and performance testing.
|
||||
|
||||
## Architecture Under Test
|
||||
|
||||
SeaweedMQ consists of:
|
||||
- **Masters**: Cluster coordination and metadata management
|
||||
- **Volume Servers**: Storage layer for persistent messages
|
||||
- **Filers**: File system interface for metadata storage
|
||||
- **Brokers**: Message processing and routing (stateless)
|
||||
- **Agents**: Client interface for pub/sub operations
|
||||
- **Schema System**: Protobuf-based message schema management
|
||||
|
||||
## Test Categories
|
||||
|
||||
### 1. Basic Functionality Tests
|
||||
|
||||
#### 1.1 Basic Pub/Sub Operations
|
||||
- **Test**: `TestBasicPublishSubscribe`
|
||||
- Publish messages to a topic
|
||||
- Subscribe and receive messages
|
||||
- Verify message content and ordering
|
||||
- Test with different data types (string, int, bytes, records)
|
||||
|
||||
- **Test**: `TestMultipleConsumers`
|
||||
- Multiple subscribers on same topic
|
||||
- Verify message distribution
|
||||
- Test consumer group functionality
|
||||
|
||||
- **Test**: `TestMessageOrdering`
|
||||
- Publish messages in sequence
|
||||
- Verify FIFO ordering within partitions
|
||||
- Test with different partition keys
|
||||
|
||||
#### 1.2 Schema Management
|
||||
- **Test**: `TestSchemaValidation`
|
||||
- Publish with valid schemas
|
||||
- Reject invalid schema messages
|
||||
- Test schema evolution scenarios
|
||||
|
||||
- **Test**: `TestRecordTypes`
|
||||
- Nested record structures
|
||||
- List types and complex schemas
|
||||
- Schema-to-Parquet conversion
|
||||
|
||||
### 2. Partitioning and Scaling Tests
|
||||
|
||||
#### 2.1 Partition Management
|
||||
- **Test**: `TestPartitionDistribution`
|
||||
- Messages distributed across partitions based on keys
|
||||
- Verify partition assignment logic
|
||||
- Test partition rebalancing
|
||||
|
||||
- **Test**: `TestAutoSplitMerge`
|
||||
- Simulate high load to trigger auto-split
|
||||
- Simulate low load to trigger auto-merge
|
||||
- Verify data consistency during splits/merges
|
||||
|
||||
#### 2.2 Broker Scaling
|
||||
- **Test**: `TestBrokerAddRemove`
|
||||
- Add brokers during operation
|
||||
- Remove brokers gracefully
|
||||
- Verify partition reassignment
|
||||
|
||||
- **Test**: `TestLoadBalancing`
|
||||
- Verify even load distribution across brokers
|
||||
- Test with varying message sizes and rates
|
||||
- Monitor broker resource utilization
|
||||
|
||||
### 3. Failover and Reliability Tests
|
||||
|
||||
#### 3.1 Broker Failover
|
||||
- **Test**: `TestBrokerFailover`
|
||||
- Kill leader broker during publishing
|
||||
- Verify seamless failover to follower
|
||||
- Test data consistency after failover
|
||||
|
||||
- **Test**: `TestBrokerRecovery`
|
||||
- Broker restart scenarios
|
||||
- State recovery from storage
|
||||
- Partition reassignment after recovery
|
||||
|
||||
#### 3.2 Data Durability
|
||||
- **Test**: `TestMessagePersistence`
|
||||
- Publish messages and restart cluster
|
||||
- Verify all messages are recovered
|
||||
- Test with different replication settings
|
||||
|
||||
- **Test**: `TestFollowerReplication`
|
||||
- Leader-follower message replication
|
||||
- Verify consistency between replicas
|
||||
- Test follower promotion scenarios
|
||||
|
||||
### 4. Agent Functionality Tests
|
||||
|
||||
#### 4.1 Session Management
|
||||
- **Test**: `TestPublishSessions`
|
||||
- Create/close publish sessions
|
||||
- Concurrent session management
|
||||
- Session cleanup after failures
|
||||
|
||||
- **Test**: `TestSubscribeSessions`
|
||||
- Subscribe session lifecycle
|
||||
- Consumer group management
|
||||
- Offset tracking and acknowledgments
|
||||
|
||||
#### 4.2 Error Handling
|
||||
- **Test**: `TestConnectionFailures`
|
||||
- Network partitions between agent and broker
|
||||
- Automatic reconnection logic
|
||||
- Message buffering during outages
|
||||
|
||||
### 5. Performance and Load Tests
|
||||
|
||||
#### 5.1 Throughput Tests
|
||||
- **Test**: `TestHighThroughputPublish`
|
||||
- Publish 100K+ messages/second
|
||||
- Monitor system resources
|
||||
- Verify no message loss
|
||||
|
||||
- **Test**: `TestHighThroughputSubscribe`
|
||||
- Multiple consumers processing high volume
|
||||
- Monitor processing latency
|
||||
- Test backpressure handling
|
||||
|
||||
#### 5.2 Spike Traffic Tests
|
||||
- **Test**: `TestTrafficSpikes`
|
||||
- Sudden increase in message volume
|
||||
- Auto-scaling behavior verification
|
||||
- Resource utilization patterns
|
||||
|
||||
- **Test**: `TestLargeMessages`
|
||||
- Messages with large payloads (MB size)
|
||||
- Memory usage monitoring
|
||||
- Storage efficiency testing
|
||||
|
||||
### 6. End-to-End Scenarios
|
||||
|
||||
#### 6.1 Complete Workflow Tests
|
||||
- **Test**: `TestProducerConsumerWorkflow`
|
||||
- Multi-stage data processing pipeline
|
||||
- Producer → Topic → Multiple Consumers
|
||||
- Data transformation and aggregation
|
||||
|
||||
- **Test**: `TestMultiTopicOperations`
|
||||
- Multiple topics with different schemas
|
||||
- Cross-topic message routing
|
||||
- Topic management operations
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
### Environment Setup
|
||||
|
||||
#### Docker Compose Configuration
|
||||
```yaml
|
||||
# test-environment.yml
|
||||
version: '3.9'
|
||||
services:
|
||||
master-cluster:
|
||||
# 3 master nodes for HA
|
||||
volume-cluster:
|
||||
# 3 volume servers for data storage
|
||||
filer-cluster:
|
||||
# 2 filers for metadata
|
||||
broker-cluster:
|
||||
# 3 brokers for message processing
|
||||
test-runner:
|
||||
# Container to run integration tests
|
||||
```
|
||||
|
||||
#### Test Data Management
|
||||
- Pre-defined test schemas
|
||||
- Sample message datasets
|
||||
- Performance benchmarking data
|
||||
|
||||
### Test Framework Structure
|
||||
|
||||
```go
|
||||
// Base test framework
|
||||
type IntegrationTestSuite struct {
|
||||
masters []string
|
||||
brokers []string
|
||||
filers []string
|
||||
testClient *TestClient
|
||||
cleanup []func()
|
||||
}
|
||||
|
||||
// Test utilities
|
||||
type TestClient struct {
|
||||
publishers map[string]*pub_client.TopicPublisher
|
||||
subscribers map[string]*sub_client.TopicSubscriber
|
||||
agents []*agent.MessageQueueAgent
|
||||
}
|
||||
```
|
||||
|
||||
### Monitoring and Metrics
|
||||
|
||||
#### Health Checks
|
||||
- Broker connectivity status
|
||||
- Master cluster health
|
||||
- Storage system availability
|
||||
- Network connectivity between components
|
||||
|
||||
#### Performance Metrics
|
||||
- Message throughput (msgs/sec)
|
||||
- End-to-end latency
|
||||
- Resource utilization (CPU, Memory, Disk)
|
||||
- Network bandwidth usage
|
||||
|
||||
## Test Execution Strategy
|
||||
|
||||
### Parallel Test Execution
|
||||
- Categorize tests by resource requirements
|
||||
- Run independent tests in parallel
|
||||
- Serialize tests that modify cluster state
|
||||
|
||||
### Continuous Integration
|
||||
- Automated test runs on PR submissions
|
||||
- Performance regression detection
|
||||
- Multi-platform testing (Linux, macOS, Windows)
|
||||
|
||||
### Test Environment Management
|
||||
- Docker-based isolated environments
|
||||
- Automatic cleanup after test completion
|
||||
- Resource monitoring and alerts
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Functional Requirements
|
||||
- ✅ All messages published are received by subscribers
|
||||
- ✅ Message ordering preserved within partitions
|
||||
- ✅ Schema validation works correctly
|
||||
- ✅ Auto-scaling triggers at expected thresholds
|
||||
- ✅ Failover completes within 30 seconds
|
||||
- ✅ No data loss during normal operations
|
||||
|
||||
### Performance Requirements
|
||||
- ✅ Throughput: 50K+ messages/second/broker
|
||||
- ✅ Latency: P95 < 100ms end-to-end
|
||||
- ✅ Memory usage: < 1GB per broker under normal load
|
||||
- ✅ Storage efficiency: < 20% overhead vs raw message size
|
||||
|
||||
### Reliability Requirements
|
||||
- ✅ 99.9% uptime during normal operations
|
||||
- ✅ Automatic recovery from single component failures
|
||||
- ✅ Data consistency maintained across all scenarios
|
||||
- ✅ Graceful degradation under resource constraints
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
### Phase 1: Core Functionality (Week 1-2)
|
||||
- Basic pub/sub tests
|
||||
- Schema validation tests
|
||||
- Simple failover scenarios
|
||||
|
||||
### Phase 2: Advanced Features (Week 3-4)
|
||||
- Auto-scaling tests
|
||||
- Complex failover scenarios
|
||||
- Agent functionality tests
|
||||
|
||||
### Phase 3: Performance & Load (Week 5-6)
|
||||
- Throughput and latency tests
|
||||
- Spike traffic handling
|
||||
- Resource utilization monitoring
|
||||
|
||||
### Phase 4: End-to-End (Week 7-8)
|
||||
- Complete workflow tests
|
||||
- Multi-component integration
|
||||
- Performance regression testing
|
||||
|
||||
## Maintenance and Updates
|
||||
|
||||
### Regular Updates
|
||||
- Add tests for new features
|
||||
- Update performance baselines
|
||||
- Enhance error scenarios coverage
|
||||
|
||||
### Test Data Refresh
|
||||
- Generate new test datasets quarterly
|
||||
- Update schema examples
|
||||
- Refresh performance benchmarks
|
||||
|
||||
This comprehensive test design ensures SeaweedMQ's reliability, performance, and functionality across all critical use cases and failure scenarios.
|
||||
@@ -0,0 +1,54 @@
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
rule_files:
|
||||
# - "first_rules.yml"
|
||||
# - "second_rules.yml"
|
||||
|
||||
scrape_configs:
|
||||
# SeaweedFS Masters
|
||||
- job_name: 'seaweedfs-master'
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'master0:9333'
|
||||
- 'master1:9334'
|
||||
- 'master2:9335'
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 10s
|
||||
|
||||
# SeaweedFS Volume Servers
|
||||
- job_name: 'seaweedfs-volume'
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'volume1:8080'
|
||||
- 'volume2:8081'
|
||||
- 'volume3:8082'
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 10s
|
||||
|
||||
# SeaweedFS Filers
|
||||
- job_name: 'seaweedfs-filer'
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'filer1:8888'
|
||||
- 'filer2:8889'
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 10s
|
||||
|
||||
# SeaweedMQ Brokers
|
||||
- job_name: 'seaweedmq-broker'
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'broker1:17777'
|
||||
- 'broker2:17778'
|
||||
- 'broker3:17779'
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 5s
|
||||
|
||||
# Docker containers
|
||||
- job_name: 'docker'
|
||||
static_configs:
|
||||
- targets: ['localhost:9323']
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 30s
|
||||
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/client/pub_client"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Starting SeaweedMQ logging test...")
|
||||
|
||||
// Create publisher configuration
|
||||
config := &pub_client.PublisherConfiguration{
|
||||
Topic: topic.NewTopic("test", "logging-demo"),
|
||||
PartitionCount: 3,
|
||||
Brokers: []string{"127.0.0.1:17777"},
|
||||
PublisherName: "logging-test-client",
|
||||
}
|
||||
|
||||
log.Println("Creating topic publisher...")
|
||||
publisher, err := pub_client.NewTopicPublisher(config)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create publisher: %v", err)
|
||||
return
|
||||
}
|
||||
defer publisher.Shutdown()
|
||||
|
||||
log.Println("Publishing test messages...")
|
||||
|
||||
// Publish some test messages
|
||||
for i := 0; i < 100; i++ {
|
||||
key := fmt.Sprintf("key-%d", i)
|
||||
value := fmt.Sprintf("message-%d-timestamp-%d", i, time.Now().Unix())
|
||||
|
||||
err := publisher.Publish([]byte(key), []byte(value))
|
||||
if err != nil {
|
||||
log.Printf("Failed to publish message %d: %v", i, err)
|
||||
}
|
||||
|
||||
// Small delay to create some connection stress
|
||||
if i%10 == 0 {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Finishing publish...")
|
||||
err = publisher.FinishPublish()
|
||||
if err != nil {
|
||||
log.Printf("Failed to finish publish: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Test completed successfully!")
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func init() {
|
||||
|
||||
var cmdMqAgent = &Command{
|
||||
UsageLine: "mq.agent [-port=16777] [-broker=<ip:port>]",
|
||||
Short: "<WIP> start a message queue agent",
|
||||
Short: "start a message queue agent",
|
||||
Long: `start a message queue agent
|
||||
|
||||
The agent runs on local server to accept gRPC calls to write or read messages.
|
||||
|
||||
@@ -43,7 +43,7 @@ func init() {
|
||||
|
||||
var cmdMqBroker = &Command{
|
||||
UsageLine: "mq.broker [-port=17777] [-master=<ip:port>]",
|
||||
Short: "<WIP> start a message queue broker",
|
||||
Short: "start a message queue broker",
|
||||
Long: `start a message queue broker
|
||||
|
||||
The broker can accept gRPC calls to write or read messages. The messages are stored via filer.
|
||||
|
||||
@@ -3,15 +3,19 @@ package broker
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"google.golang.org/grpc/peer"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// PUB
|
||||
@@ -126,7 +130,12 @@ func (b *MessageQueueBroker) PublishMessage(stream mq_pb.SeaweedMessaging_Publis
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
glog.V(0).Infof("topic %v partition %v publish stream from %s error: %v", initMessage.Topic, initMessage.Partition, initMessage.PublisherName, err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(err) {
|
||||
glog.V(1).Infof("topic %v partition %v publish stream from %s connection error (client disconnected): %v", initMessage.Topic, initMessage.Partition, initMessage.PublisherName, err)
|
||||
} else {
|
||||
glog.V(0).Infof("topic %v partition %v publish stream from %s error: %v", initMessage.Topic, initMessage.Partition, initMessage.PublisherName, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -145,7 +154,7 @@ func (b *MessageQueueBroker) PublishMessage(stream mq_pb.SeaweedMessaging_Publis
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(0).Infof("topic %v partition %v publish stream from %s closed.", initMessage.Topic, initMessage.Partition, initMessage.PublisherName)
|
||||
glog.V(1).Infof("topic %v partition %v publish stream from %s closed.", initMessage.Topic, initMessage.Partition, initMessage.PublisherName)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -164,3 +173,40 @@ func findClientAddress(ctx context.Context) string {
|
||||
}
|
||||
return pr.Addr.String()
|
||||
}
|
||||
|
||||
// isConnectionError checks if an error is a connection-level error
|
||||
func isConnectionError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check gRPC status codes for connection errors
|
||||
if grpcStatus, ok := status.FromError(err); ok {
|
||||
switch grpcStatus.Code() {
|
||||
case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled, codes.Unknown:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common connection error patterns
|
||||
errStr := strings.ToLower(err.Error())
|
||||
connectionErrorPatterns := []string{
|
||||
"eof",
|
||||
"error reading server preface",
|
||||
"connection refused",
|
||||
"connection reset",
|
||||
"broken pipe",
|
||||
"no such host",
|
||||
"network is unreachable",
|
||||
"context deadline exceeded",
|
||||
"context canceled",
|
||||
}
|
||||
|
||||
for _, pattern := range connectionErrorPatterns {
|
||||
if strings.Contains(errStr, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ package broker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/buffered_queue"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/log_buffer"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type memBuffer struct {
|
||||
@@ -43,7 +44,12 @@ func (b *MessageQueueBroker) PublishFollowMe(stream mq_pb.SeaweedMessaging_Publi
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
glog.V(0).Infof("topic %v partition %v publish stream error: %v", initMessage.Topic, initMessage.Partition, err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(err) {
|
||||
glog.V(1).Infof("topic %v partition %v publish follower stream connection error (leader disconnected): %v", initMessage.Topic, initMessage.Partition, err)
|
||||
} else {
|
||||
glog.V(0).Infof("topic %v partition %v publish stream error: %v", initMessage.Topic, initMessage.Partition, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -62,10 +68,10 @@ func (b *MessageQueueBroker) PublishFollowMe(stream mq_pb.SeaweedMessaging_Publi
|
||||
}
|
||||
// println("ack", string(dataMessage.Key), dataMessage.TsNs)
|
||||
} else if closeMessage := req.GetClose(); closeMessage != nil {
|
||||
glog.V(0).Infof("topic %v partition %v publish stream closed: %v", initMessage.Topic, initMessage.Partition, closeMessage)
|
||||
glog.V(1).Infof("topic %v partition %v publish stream closed: %v", initMessage.Topic, initMessage.Partition, closeMessage)
|
||||
break
|
||||
} else if flushMessage := req.GetFlush(); flushMessage != nil {
|
||||
glog.V(0).Infof("topic %v partition %v publish stream flushed: %v", initMessage.Topic, initMessage.Partition, flushMessage)
|
||||
glog.V(1).Infof("topic %v partition %v publish stream flushed: %v", initMessage.Topic, initMessage.Partition, flushMessage)
|
||||
|
||||
lastFlushTsNs = flushMessage.TsNs
|
||||
|
||||
@@ -124,7 +130,7 @@ func (b *MessageQueueBroker) PublishFollowMe(stream mq_pb.SeaweedMessaging_Publi
|
||||
glog.V(0).Infof("flushed remaining data at %v to %s size %d", mem.stopTime.UnixNano(), targetFile, len(mem.buf))
|
||||
}
|
||||
|
||||
glog.V(0).Infof("shut down follower for %v %v", t, p)
|
||||
glog.V(1).Infof("shut down follower for %v %v", t, p)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,13 @@ package pub_client
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
@@ -11,11 +18,6 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/status"
|
||||
"log"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EachPartitionError struct {
|
||||
@@ -39,7 +41,7 @@ func (p *TopicPublisher) startSchedulerThread(wg *sync.WaitGroup) error {
|
||||
return fmt.Errorf("configure topic %s: %v", p.config.Topic, err)
|
||||
}
|
||||
|
||||
log.Printf("start scheduler thread for topic %s", p.config.Topic)
|
||||
glog.V(0).Infof("start scheduler thread for topic %s", p.config.Topic)
|
||||
|
||||
generation := 0
|
||||
var errChan chan EachPartitionError
|
||||
@@ -66,7 +68,12 @@ func (p *TopicPublisher) startSchedulerThread(wg *sync.WaitGroup) error {
|
||||
for {
|
||||
select {
|
||||
case eachErr := <-errChan:
|
||||
glog.Errorf("gen %d publish to topic %s partition %v: %v", eachErr.generation, p.config.Topic, eachErr.Partition, eachErr.Err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(eachErr.Err) {
|
||||
glog.V(1).Infof("gen %d connection error for topic %s partition %v (will retry): %v", eachErr.generation, p.config.Topic, eachErr.Partition, eachErr.Err)
|
||||
} else {
|
||||
glog.Errorf("gen %d publish to topic %s partition %v: %v", eachErr.generation, p.config.Topic, eachErr.Partition, eachErr.Err)
|
||||
}
|
||||
if eachErr.generation < generation {
|
||||
continue
|
||||
}
|
||||
@@ -114,7 +121,12 @@ func (p *TopicPublisher) onEachAssignments(generation int, assignments []*mq_pb.
|
||||
go func(job *EachPartitionPublishJob) {
|
||||
defer job.wg.Done()
|
||||
if err := p.doPublishToPartition(job); err != nil {
|
||||
log.Printf("publish to %s partition %v: %v", p.config.Topic, job.Partition, err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(err) {
|
||||
glog.V(1).Infof("connection error publishing to %s partition %v (will retry): %v", p.config.Topic, job.Partition, err)
|
||||
} else {
|
||||
log.Printf("publish to %s partition %v: %v", p.config.Topic, job.Partition, err)
|
||||
}
|
||||
errChan <- EachPartitionError{assignment, err, generation}
|
||||
}
|
||||
}(job)
|
||||
@@ -128,7 +140,7 @@ func (p *TopicPublisher) onEachAssignments(generation int, assignments []*mq_pb.
|
||||
|
||||
func (p *TopicPublisher) doPublishToPartition(job *EachPartitionPublishJob) error {
|
||||
|
||||
log.Printf("connecting to %v for topic partition %+v", job.LeaderBroker, job.Partition)
|
||||
glog.V(1).Infof("connecting to %v for topic partition %+v", job.LeaderBroker, job.Partition)
|
||||
|
||||
grpcConnection, err := grpc.NewClient(job.LeaderBroker, grpc.WithTransportCredentials(insecure.NewCredentials()), p.grpcDialOption)
|
||||
if err != nil {
|
||||
@@ -176,20 +188,25 @@ func (p *TopicPublisher) doPublishToPartition(job *EachPartitionPublishJob) erro
|
||||
if err != nil {
|
||||
e, _ := status.FromError(err)
|
||||
if e.Code() == codes.Unknown && e.Message() == "EOF" {
|
||||
log.Printf("publish to %s EOF", publishClient.Broker)
|
||||
glog.V(1).Infof("publish stream to %s closed (EOF)", publishClient.Broker)
|
||||
return
|
||||
}
|
||||
publishClient.Err = err
|
||||
log.Printf("publish1 to %s error: %v\n", publishClient.Broker, err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(err) {
|
||||
glog.V(1).Infof("connection error receiving from %s (will retry): %v", publishClient.Broker, err)
|
||||
} else {
|
||||
log.Printf("publish receive error from %s: %v", publishClient.Broker, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if ackResp.Error != "" {
|
||||
publishClient.Err = fmt.Errorf("ack error: %v", ackResp.Error)
|
||||
log.Printf("publish2 to %s error: %v\n", publishClient.Broker, ackResp.Error)
|
||||
log.Printf("publish ack error from %s: %v", publishClient.Broker, ackResp.Error)
|
||||
return
|
||||
}
|
||||
if ackResp.AckSequence > 0 {
|
||||
log.Printf("ack %d published %d hasMoreData:%d", ackResp.AckSequence, atomic.LoadInt64(&publishedTsNs), atomic.LoadInt32(&hasMoreData))
|
||||
glog.V(2).Infof("ack %d published %d hasMoreData:%d", ackResp.AckSequence, atomic.LoadInt64(&publishedTsNs), atomic.LoadInt32(&hasMoreData))
|
||||
}
|
||||
if atomic.LoadInt64(&publishedTsNs) <= ackResp.AckSequence && atomic.LoadInt32(&hasMoreData) == 0 {
|
||||
return
|
||||
@@ -222,7 +239,7 @@ func (p *TopicPublisher) doPublishToPartition(job *EachPartitionPublishJob) erro
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("published %d messages to %v for topic partition %+v", publishCounter, job.LeaderBroker, job.Partition)
|
||||
glog.V(1).Infof("published %d messages to %v for topic partition %+v", publishCounter, job.LeaderBroker, job.Partition)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -296,3 +313,40 @@ func (p *TopicPublisher) doLookupTopicPartitions() (assignments []*mq_pb.BrokerP
|
||||
return nil, fmt.Errorf("lookup topic %s: %v", p.config.Topic, lastErr)
|
||||
|
||||
}
|
||||
|
||||
// isConnectionError checks if an error is a connection-level error that is handled automatically
|
||||
func isConnectionError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check gRPC status codes for connection errors
|
||||
if grpcStatus, ok := status.FromError(err); ok {
|
||||
switch grpcStatus.Code() {
|
||||
case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled, codes.Unknown:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common connection error patterns
|
||||
errStr := strings.ToLower(err.Error())
|
||||
connectionErrorPatterns := []string{
|
||||
"eof",
|
||||
"error reading server preface",
|
||||
"connection refused",
|
||||
"connection reset",
|
||||
"broken pipe",
|
||||
"no such host",
|
||||
"network is unreachable",
|
||||
"context deadline exceeded",
|
||||
"context canceled",
|
||||
}
|
||||
|
||||
for _, pattern := range connectionErrorPatterns {
|
||||
if strings.Contains(errStr, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/parquet-go/parquet-go"
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/schema"
|
||||
@@ -13,9 +17,6 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/chunk_cache"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/log_buffer"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -42,10 +43,6 @@ func GenParquetReadFunc(filerClient filer_pb.FilerClient, t topic.Topic, p topic
|
||||
WithField(SW_COLUMN_NAME_KEY, schema.TypeBytes).
|
||||
RecordTypeEnd()
|
||||
|
||||
parquetSchema, err := schema.ToParquetSchema(t.Name, recordType)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
parquetLevels, err := schema.ToParquetLevels(recordType)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -61,11 +58,12 @@ func GenParquetReadFunc(filerClient filer_pb.FilerClient, t topic.Topic, p topic
|
||||
readerAt := filer.NewChunkReaderAtFromClient(readerCache, chunkViews, int64(fileSize))
|
||||
|
||||
// create parquet reader
|
||||
parquetReader := parquet.NewReader(readerAt, parquetSchema)
|
||||
parquetReader := parquet.NewReader(readerAt)
|
||||
rows := make([]parquet.Row, 128)
|
||||
for {
|
||||
rowCount, readErr := parquetReader.ReadRows(rows)
|
||||
|
||||
// Process the rows first, even if EOF is returned
|
||||
for i := 0; i < rowCount; i++ {
|
||||
row := rows[i]
|
||||
// convert parquet row to schema_pb.RecordValue
|
||||
@@ -99,12 +97,16 @@ func GenParquetReadFunc(filerClient filer_pb.FilerClient, t topic.Topic, p topic
|
||||
}
|
||||
}
|
||||
|
||||
// Check for end conditions after processing rows
|
||||
if readErr != nil {
|
||||
if readErr == io.EOF {
|
||||
return processedTsNs, nil
|
||||
}
|
||||
return processedTsNs, readErr
|
||||
}
|
||||
if rowCount == 0 {
|
||||
return processedTsNs, nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ package schema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/parquet-go/parquet-go"
|
||||
"github.com/parquet-go/parquet-go/compress/zstd"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/parquet-go/parquet-go"
|
||||
"github.com/parquet-go/parquet-go/compress/zstd"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
)
|
||||
|
||||
func TestWriteReadParquet(t *testing.T) {
|
||||
@@ -125,16 +126,25 @@ func testReadingParquetFile(t *testing.T, filename string, parquetSchema *parque
|
||||
t.Fatalf("os.Open failed: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
reader := parquet.NewReader(file, parquetSchema)
|
||||
|
||||
// Get file info to determine size
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
t.Fatalf("file.Stat failed: %v", err)
|
||||
}
|
||||
|
||||
// Create a parquet file from the opened file
|
||||
parquetFile, err := parquet.OpenFile(file, fileInfo.Size())
|
||||
if err != nil {
|
||||
t.Fatalf("parquet.OpenFile failed: %v", err)
|
||||
}
|
||||
|
||||
reader := parquet.NewReader(parquetFile)
|
||||
rows := make([]parquet.Row, 128)
|
||||
for {
|
||||
rowCount, err := reader.ReadRows(rows)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Fatalf("reader.Read failed: %v", err)
|
||||
}
|
||||
|
||||
// Process the rows first, even if EOF is returned
|
||||
for i := 0; i < rowCount; i++ {
|
||||
row := rows[i]
|
||||
// convert parquet row to schema_pb.RecordValue
|
||||
@@ -147,6 +157,17 @@ func testReadingParquetFile(t *testing.T, filename string, parquetSchema *parque
|
||||
}
|
||||
}
|
||||
total += rowCount
|
||||
|
||||
// Check for end conditions after processing rows
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Fatalf("reader.Read failed: %v", err)
|
||||
}
|
||||
if rowCount == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Printf("total: %v\n", total)
|
||||
return
|
||||
|
||||
@@ -3,6 +3,11 @@ package topic
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
@@ -10,9 +15,6 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LocalPartition struct {
|
||||
@@ -182,7 +184,12 @@ func (p *LocalPartition) MaybeConnectToFollowers(initMessage *mq_pb.PublishMessa
|
||||
glog.V(0).Infof("local partition %v follower %v stopped", p.Partition, p.Follower)
|
||||
return
|
||||
}
|
||||
glog.Errorf("Receiving local partition %v follower %s ack: %v", p.Partition, p.Follower, err)
|
||||
// Use appropriate logging level based on error type
|
||||
if isConnectionError(err) {
|
||||
glog.V(1).Infof("local partition %v follower %s connection error (will retry): %v", p.Partition, p.Follower, err)
|
||||
} else {
|
||||
glog.Errorf("Receiving local partition %v follower %s ack: %v", p.Partition, p.Follower, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
atomic.StoreInt64(&p.AckTsNs, ack.AckTsNs)
|
||||
@@ -242,3 +249,40 @@ func (p *LocalPartition) NotifyLogFlushed(flushTsNs int64) {
|
||||
// println("notifying", p.Follower, "flushed at", flushTsNs)
|
||||
}
|
||||
}
|
||||
|
||||
// isConnectionError checks if an error is a connection-level error
|
||||
func isConnectionError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check gRPC status codes for connection errors
|
||||
if grpcStatus, ok := status.FromError(err); ok {
|
||||
switch grpcStatus.Code() {
|
||||
case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled, codes.Unknown:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common connection error patterns
|
||||
errStr := strings.ToLower(err.Error())
|
||||
connectionErrorPatterns := []string{
|
||||
"eof",
|
||||
"error reading server preface",
|
||||
"connection refused",
|
||||
"connection reset",
|
||||
"broken pipe",
|
||||
"no such host",
|
||||
"network is unreachable",
|
||||
"context deadline exceeded",
|
||||
"context canceled",
|
||||
}
|
||||
|
||||
for _, pattern := range connectionErrorPatterns {
|
||||
if strings.Contains(errStr, pattern) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user