From 2bc28c11bb90f406971119b18bf9e3adaf89ae7c Mon Sep 17 00:00:00 2001 From: Bychkov Date: Thu, 13 Jun 2024 17:43:43 +0300 Subject: [PATCH 01/10] testcontainers-go integration --- .github/workflows/main.yml | 350 +++++++++++++++++--------------- cassandra_test.go | 6 +- go.mod | 61 +++++- go.sum | 199 +++++++++++++++++- main_test.go | 127 ++++++++++++ update_container_cass_config.sh | 113 +++++++++++ 6 files changed, 676 insertions(+), 180 deletions(-) create mode 100644 main_test.go create mode 100755 update_container_cass_config.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d2044a0c0..5637e913a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.22', '1.23' ] + go: [ '1.20' ] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 @@ -25,177 +25,201 @@ jobs: - run: go vet - name: Run unit tests run: go test -v -tags unit -race - integration-cassandra: - timeout-minutes: 15 - needs: - - build - name: Integration Tests +# integration-cassandra: +# timeout-minutes: 15 +# needs: +# - build +# name: Integration Tests +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# go: [ '1.19', '1.20' ] +# cassandra_version: [ '4.0.8', '4.1.1' ] +# auth: [ "false" ] +# compressor: [ "snappy" ] +# tags: [ "cassandra", "integration", "ccm" ] +# steps: +# - uses: actions/checkout@v2 +# - uses: actions/setup-go@v2 +# with: +# go-version: ${{ matrix.go }} +# - uses: actions/cache@v2 +# id: gomod-cache +# with: +# path: ~/go/pkg/mod +# key: ${{ runner.os }}-go-${{ hashFiles('go.mod') }} +# restore-keys: | +# ${{ runner.os }}-go- +# - name: Install CCM +# run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" +# - name: Start cassandra nodes +# run: | +# VERSION=${{ matrix.cassandra_version }} +# keypath="$(pwd)/testdata/pki" +# conf=( +# "client_encryption_options.enabled: true" +# "client_encryption_options.keystore: $keypath/.keystore" +# "client_encryption_options.keystore_password: cassandra" +# "client_encryption_options.require_client_auth: true" +# "client_encryption_options.truststore: $keypath/.truststore" +# "client_encryption_options.truststore_password: cassandra" +# "concurrent_reads: 2" +# "concurrent_writes: 2" +# "write_request_timeout_in_ms: 5000" +# "read_request_timeout_in_ms: 5000" +# ) +# +# if [[ $VERSION == 3.*.* ]]; then +# conf+=( +# "rpc_server_type: sync" +# "rpc_min_threads: 2" +# "rpc_max_threads: 2" +# "enable_user_defined_functions: true" +# "enable_materialized_views: true" +# ) +# elif [[ $VERSION == 4.0.* ]]; then +# conf+=( +# "enable_user_defined_functions: true" +# "enable_materialized_views: true" +# ) +# else +# conf+=( +# "user_defined_functions_enabled: true" +# "materialized_views_enabled: true" +# ) +# fi +# +# ccm remove test || true +# +# ccm create test -v $VERSION -n 3 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" +# ccm updateconf "${conf[@]}" +# +# export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" +# +# ccm start --wait-for-binary-proto --verbose +# ccm status +# ccm node1 nodetool status +# +# args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." +# +# echo "args=$args" >> $GITHUB_ENV +# echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV +# - name: Integration tests +# run: | +# export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" +# go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} +# - name: 'Save ccm logs' +# if: 'failure()' +# uses: actions/upload-artifact@v3 +# with: +# name: ccm-cluster +# path: /home/runner/.ccm/test +# retention-days: 5 +# integration-auth-cassandra: +# timeout-minutes: 15 +# needs: +# - build +# name: Integration Tests with auth +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# go: [ '1.19', '1.20' ] +# cassandra_version: [ '4.0.8' ] +# compressor: [ "snappy" ] +# tags: [ "integration" ] +# +# steps: +# - uses: actions/checkout@v3 +# - uses: actions/setup-go@v4 +# with: +# go-version: ${{ matrix.go }} +# - name: Install CCM +# run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" +# - name: Start cassandra nodes +# run: | +# VERSION=${{ matrix.cassandra_version }} +# keypath="$(pwd)/testdata/pki" +# conf=( +# "client_encryption_options.enabled: true" +# "client_encryption_options.keystore: $keypath/.keystore" +# "client_encryption_options.keystore_password: cassandra" +# "client_encryption_options.require_client_auth: true" +# "client_encryption_options.truststore: $keypath/.truststore" +# "client_encryption_options.truststore_password: cassandra" +# "concurrent_reads: 2" +# "concurrent_writes: 2" +# "write_request_timeout_in_ms: 5000" +# "read_request_timeout_in_ms: 5000" +# "authenticator: PasswordAuthenticator" +# "authorizer: CassandraAuthorizer" +# "enable_user_defined_functions: true" +# ) +# +# if [[ $VERSION == 3.*.* ]]; then +# conf+=( +# "rpc_server_type: sync" +# "rpc_min_threads: 2" +# "rpc_max_threads: 2" +# "enable_user_defined_functions: true" +# "enable_materialized_views: true" +# ) +# elif [[ $VERSION == 4.0.* ]]; then +# conf+=( +# "enable_user_defined_functions: true" +# "enable_materialized_views: true" +# ) +# else +# conf+=( +# "user_defined_functions_enabled: true" +# "materialized_views_enabled: true" +# ) +# fi +# +# ccm remove test || true +# +# ccm create test -v $VERSION -n 1 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" +# ccm updateconf "${conf[@]}" +# +# rm -rf $HOME/.ccm/test/node1/data/system_auth +# +# export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" +# +# ccm start --wait-for-binary-proto --verbose +# ccm status +# ccm node1 nodetool status +# +# args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." +# +# echo "args=$args" >> $GITHUB_ENV +# echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV +# sleep 30s +# - name: Integration tests +# run: | +# export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" +# go test -v -run=TestAuthentication -tags "${{ matrix.tags }} gocql_debug" -timeout=15s -runauth ${{ env.args }} +# + integration-testscontainers: + needs: build runs-on: ubuntu-latest + name: testcontainers-go strategy: - fail-fast: false matrix: - go: [ '1.22', '1.23' ] - cassandra_version: [ '4.0.13', '4.1.6' ] + go: [ '1.20' ] + cassandra_version: [ '4.0.8', '4.1.1' ] auth: [ "false" ] compressor: [ "snappy" ] - tags: [ "cassandra", "integration", "ccm" ] + tags: [ "cassandra", "integration"] steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: go-version: ${{ matrix.go }} - - uses: actions/cache@v2 - id: gomod-cache - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('go.mod') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Install CCM - run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" - - name: Start cassandra nodes + - name: setup run: | - VERSION=${{ matrix.cassandra_version }} - keypath="$(pwd)/testdata/pki" - conf=( - "client_encryption_options.enabled: true" - "client_encryption_options.keystore: $keypath/.keystore" - "client_encryption_options.keystore_password: cassandra" - "client_encryption_options.require_client_auth: true" - "client_encryption_options.truststore: $keypath/.truststore" - "client_encryption_options.truststore_password: cassandra" - "concurrent_reads: 2" - "concurrent_writes: 2" - "write_request_timeout_in_ms: 5000" - "read_request_timeout_in_ms: 5000" - ) - - if [[ $VERSION == 3.*.* ]]; then - conf+=( - "rpc_server_type: sync" - "rpc_min_threads: 2" - "rpc_max_threads: 2" - "enable_user_defined_functions: true" - "enable_materialized_views: true" - ) - elif [[ $VERSION == 4.0.* ]]; then - conf+=( - "enable_user_defined_functions: true" - "enable_materialized_views: true" - ) - else - conf+=( - "user_defined_functions_enabled: true" - "materialized_views_enabled: true" - ) - fi - - ccm remove test || true - - ccm create test -v $VERSION -n 3 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" - ccm updateconf "${conf[@]}" - - export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" - - ccm start --wait-for-binary-proto --verbose - ccm status - ccm node1 nodetool status - - args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." - + args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." echo "args=$args" >> $GITHUB_ENV - echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV - - name: Integration tests - run: | - export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" - go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} - - name: 'Save ccm logs' - if: 'failure()' - uses: actions/upload-artifact@v3 - with: - name: ccm-cluster - path: /home/runner/.ccm/test - retention-days: 5 - integration-auth-cassandra: - timeout-minutes: 15 - needs: - - build - name: Integration Tests with auth - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - go: [ '1.22', '1.23' ] - cassandra_version: [ '4.0.13' ] - compressor: [ "snappy" ] - tags: [ "integration" ] - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go }} - - name: Install CCM - run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" - - name: Start cassandra nodes - run: | - VERSION=${{ matrix.cassandra_version }} - keypath="$(pwd)/testdata/pki" - conf=( - "client_encryption_options.enabled: true" - "client_encryption_options.keystore: $keypath/.keystore" - "client_encryption_options.keystore_password: cassandra" - "client_encryption_options.require_client_auth: true" - "client_encryption_options.truststore: $keypath/.truststore" - "client_encryption_options.truststore_password: cassandra" - "concurrent_reads: 2" - "concurrent_writes: 2" - "write_request_timeout_in_ms: 5000" - "read_request_timeout_in_ms: 5000" - "authenticator: PasswordAuthenticator" - "authorizer: CassandraAuthorizer" - "enable_user_defined_functions: true" - ) - - if [[ $VERSION == 3.*.* ]]; then - conf+=( - "rpc_server_type: sync" - "rpc_min_threads: 2" - "rpc_max_threads: 2" - "enable_user_defined_functions: true" - "enable_materialized_views: true" - ) - elif [[ $VERSION == 4.0.* ]]; then - conf+=( - "enable_user_defined_functions: true" - "enable_materialized_views: true" - ) - else - conf+=( - "user_defined_functions_enabled: true" - "materialized_views_enabled: true" - ) - fi - - ccm remove test || true - - ccm create test -v $VERSION -n 1 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" - ccm updateconf "${conf[@]}" - - rm -rf $HOME/.ccm/test/node1/data/system_auth - - export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" - - ccm start --wait-for-binary-proto --verbose - ccm status - ccm node1 nodetool status - - args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." - - echo "args=$args" >> $GITHUB_ENV - echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV - sleep 30s - - name: Integration tests - run: | - export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" - go test -v -run=TestAuthentication -tags "${{ matrix.tags }} gocql_debug" -timeout=15s -runauth ${{ env.args }} + - name: run + run: | + go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} diff --git a/cassandra_test.go b/cassandra_test.go index 797a7cf7f..9401eb1e6 100644 --- a/cassandra_test.go +++ b/cassandra_test.go @@ -3029,14 +3029,12 @@ func TestDiscoverViaProxy(t *testing.T) { session := createSessionFromCluster(cluster, t) defer session.Close() - // we shouldnt need this but to be safe - time.Sleep(1 * time.Second) - session.pool.mu.RLock() + for _, host := range clusterHosts { found := false for _, hi := range session.pool.hostConnPools { - if hi.host.ConnectAddress().String() == host { + if hi.host.RPCAddress().String() == host { found = true break } diff --git a/go.mod b/go.mod index 0aea881ec..c0fe6133a 100644 --- a/go.mod +++ b/go.mod @@ -18,13 +18,64 @@ module github.com/gocql/gocql require ( - github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/golang/snappy v0.0.3 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed - github.com/kr/pretty v0.1.0 // indirect - github.com/stretchr/testify v1.3.0 // indirect + github.com/testcontainers/testcontainers-go v0.31.0 gopkg.in/inf.v0 v0.9.1 ) -go 1.13 +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/containerd/containerd v1.7.15 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/docker v25.0.5+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/tools v0.13.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d // indirect + google.golang.org/grpc v1.58.3 // indirect + google.golang.org/protobuf v1.33.0 // indirect +) + +go 1.21 diff --git a/go.sum b/go.sum index 2e3892bcb..9075e7dee 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,205 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= +github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/containerd/containerd v1.7.15 h1:afEHXdil9iAm03BmhjzKyXnnEBtjaLJefdU7DV0IFes= +github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= +github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +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= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U= +github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d h1:pgIUhmqwKOUlnKna4r6amKdUngdL8DrkpFeV8+VBElY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/main_test.go b/main_test.go new file mode 100644 index 000000000..ce0a71d1a --- /dev/null +++ b/main_test.go @@ -0,0 +1,127 @@ +//go:build cassandra || integration +// +build cassandra integration + +package gocql + +import ( + "context" + "flag" + "fmt" + "log" + "os" + "strconv" + "testing" + "time" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +func TestMain(m *testing.M) { + ctx := context.Background() + + flag.Parse() + + networkRequest := testcontainers.GenericNetworkRequest{ + NetworkRequest: testcontainers.NetworkRequest{ + Name: "cassandra", + }, + } + cassandraNetwork, err := testcontainers.GenericNetwork(ctx, networkRequest) + if err != nil { + log.Fatalf("Failed to create network: %s", err) + } + defer cassandraNetwork.Remove(ctx) + + cassandraVersion := flagCassVersion.String()[1:] + // Function to create a Cassandra container (node) + createCassandraContainer := func(number int) (string, error) { + req := testcontainers.ContainerRequest{ + Image: "cassandra:" + cassandraVersion, + ExposedPorts: []string{"9042/tcp"}, + Env: map[string]string{ + "JVM_OPTS": "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler", + "CASSANDRA_SEEDS": "cassandra1", + "CASSANDRA_DC": "datacenter1", + "HEAP_NEWSIZE": "100M", + "MAX_HEAP_SIZE": "256M", + "CASSANDRA_RACK": "rack1", + "CASSANDRA_ENDPOINT_SNITCH": "GossipingPropertyFileSnitch", + "CASS_VERSION": cassandraVersion, + }, + Files: []testcontainers.ContainerFile{ + { + HostFilePath: "./testdata/pki/.keystore", + ContainerFilePath: "testdata/.keystore", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/.truststore", + ContainerFilePath: "testdata/.truststore", + FileMode: 0o777, + }, + { + HostFilePath: "update_container_cass_config.sh", + ContainerFilePath: "/update_container_cass_config.sh", + FileMode: 0o777, + }, + }, + + Networks: []string{"cassandra"}, + LifecycleHooks: []testcontainers.ContainerLifecycleHooks{{ + PostStarts: []testcontainers.ContainerHook{ + func(ctx context.Context, c testcontainers.Container) error { + // wait for cassandra config to initialize + time.Sleep(100 * time.Millisecond) + + code, _, err := c.Exec(ctx, []string{"bash", "./update_container_cass_config.sh"}) + if err != nil { + return err + } + if code != 0 { + return fmt.Errorf("script ./update_container_cass_config.sh exited with code %d", code) + } + return nil + }, + }, + }}, + WaitingFor: wait.ForLog("Startup complete").WithStartupTimeout(2 * time.Minute), + Name: "cassandra" + strconv.Itoa(number), + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return "", err + } + + ip, err := container.ContainerIP(ctx) + if err != nil { + return "", err + } + + return ip, nil + } + + // collect cass nodes into a cluster + *flagCluster = "" + for i := 0; i < *clusterSize; i++ { + ip, err := createCassandraContainer(i + 1) + if err != nil { + log.Fatalf("Failed to start Cassandra node %d: %v", i+1, err) + } + + // if not the last iteration + if i != *clusterSize-1 { + ip += "," + } + + *flagCluster += ip + } + + // run all tests + code := m.Run() + + os.Exit(code) +} diff --git a/update_container_cass_config.sh b/update_container_cass_config.sh new file mode 100755 index 000000000..b768f2911 --- /dev/null +++ b/update_container_cass_config.sh @@ -0,0 +1,113 @@ +#!/bin/bash + +# Path to the cassandra.yaml file inside the container +CASSANDRA_CONFIG="/etc/cassandra/cassandra.yaml" + +# Function to update a property in the cassandra.yaml file +update_property() { + local property=$1 + local value=$2 + local root_property=${property%%.*} + local nested_property=${property#*.} + + local indent="" + if [[ $CASS_VERSION == 4.0.* ]]; then + indent=" " + elif [[ $CASS_VERSION == 4.1.* ]]; then + indent=" " + else + indent=" " + fi + + if grep -q "^${property}:" "$CASSANDRA_CONFIG"; then + # If the property exists, update its value + sed -i "s|^\(${property}:\).*|\1 ${value}|" "$CASSANDRA_CONFIG" +# echo "Updated $property to $value" + else + if [[ "$property" == *"."* ]]; then + # If it's a nested property + if grep -q "^${root_property}:" "$CASSANDRA_CONFIG"; then + if grep -q "^${indent}# ${nested_property}:" "$CASSANDRA_CONFIG"; then + # Check if the nested property is commented out + sed -i "/^${root_property}:/,/^[^ ]/ s|^\(${indent}# ${nested_property}:\).*|${indent}${nested_property}: ${value}|" "$CASSANDRA_CONFIG" + elif grep -q "^${indent}${nested_property}:" "$CASSANDRA_CONFIG"; then + echo "Added nested_property $nested_property into root_property $root_property with value $value" + sed -i "/^${root_property}:/,/^[^ ]/ s|^\(${indent}${nested_property}:\).*|\1 ${value}|" "$CASSANDRA_CONFIG" + else + # Add nested property under existing root property + awk -v root="$root_property" -v prop="$nested_property" -v val="$value" -v ind="$indent" ' + $0 ~ "^"root":" { + print $0 + print ind prop": "val + next + } + { print $0 } + ' "$CASSANDRA_CONFIG" > tmpfile && mv tmpfile "$CASSANDRA_CONFIG" + fi + else + # Add new root property with nested property + echo -e "${root_property}:\n${indent}${nested_property}: ${value}" >> "$CASSANDRA_CONFIG" + fi + else + # If it's a root-level property, add it directly + echo "${property}: ${value}" >> "$CASSANDRA_CONFIG" + fi + fi +} + +# Function to configure Cassandra based on the version +configure_cassandra() { + local keypath="testdata" + local conf=( + "client_encryption_options.enabled:true" + "client_encryption_options.keystore:$keypath/.keystore" + "client_encryption_options.keystore_password:cassandra" + "client_encryption_options.require_client_auth:true" + "client_encryption_options.truststore:$keypath/.truststore" + "client_encryption_options.truststore_password:cassandra" + "concurrent_reads:2" + "concurrent_writes:2" + ) + + if [[ $CASS_VERSION == 3.*.* ]]; then + conf+=( + "rpc_server_type:sync" + "rpc_min_threads:2" + "rpc_max_threads:2" + "enable_user_defined_functions:true" + "enable_materialized_views:true" + "write_request_timeout_in_ms:5000" + "read_request_timeout_in_ms:5000" + ) + elif [[ $CASS_VERSION == 4.0.* ]]; then + conf+=( + "enable_user_defined_functions:true" + "enable_materialized_views:true" + "write_request_timeout_in_ms:5000" + "read_request_timeout_in_ms:5000" + ) + else + conf+=( + "user_defined_functions_enabled:true" + "materialized_views_enabled:true" + "write_request_timeout:5000ms" + "read_request_timeout:5000ms" + ) + fi + + for setting in "${conf[@]}"; do + IFS=":" read -r property value <<< "$setting" + update_property "$property" "$value" + done +} + +# update Cassandra config +configure_cassandra + +# Update rpc addresses with the container's IP address +IP_ADDRESS=$(hostname -i) +sed -i "s/^rpc_address:.*/rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml +sed -i "s/^# broadcast_rpc_address:.*/broadcast_rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml + +echo "Cassandra configuration modified successfully." + From 472fb2b1d1776083deea5d51b09d03ac78ae049b Mon Sep 17 00:00:00 2001 From: Bychkov Date: Thu, 25 Jul 2024 18:35:15 +0300 Subject: [PATCH 02/10] auth test --- .github/workflows/main.yml | 213 +++++--------------------------- CHANGELOG.md | 5 +- NOTICE | 1 + go.mod | 35 +++--- go.sum | 92 +++++++------- main_test.go | 42 +++++-- update_container_cass_config.sh | 7 ++ 7 files changed, 132 insertions(+), 263 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5637e913a..d20f503ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,16 +7,13 @@ on: pull_request: types: [ opened, synchronize, reopened ] -env: - CCM_VERSION: "6e71061146f7ae67b84ccd2b1d90d7319b640e4c" - jobs: build: name: Unit tests runs-on: ubuntu-latest strategy: matrix: - go: [ '1.20' ] + go: [ '1.20', '1.21' ] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 @@ -25,195 +22,21 @@ jobs: - run: go vet - name: Run unit tests run: go test -v -tags unit -race -# integration-cassandra: -# timeout-minutes: 15 -# needs: -# - build -# name: Integration Tests -# runs-on: ubuntu-latest -# strategy: -# fail-fast: false -# matrix: -# go: [ '1.19', '1.20' ] -# cassandra_version: [ '4.0.8', '4.1.1' ] -# auth: [ "false" ] -# compressor: [ "snappy" ] -# tags: [ "cassandra", "integration", "ccm" ] -# steps: -# - uses: actions/checkout@v2 -# - uses: actions/setup-go@v2 -# with: -# go-version: ${{ matrix.go }} -# - uses: actions/cache@v2 -# id: gomod-cache -# with: -# path: ~/go/pkg/mod -# key: ${{ runner.os }}-go-${{ hashFiles('go.mod') }} -# restore-keys: | -# ${{ runner.os }}-go- -# - name: Install CCM -# run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" -# - name: Start cassandra nodes -# run: | -# VERSION=${{ matrix.cassandra_version }} -# keypath="$(pwd)/testdata/pki" -# conf=( -# "client_encryption_options.enabled: true" -# "client_encryption_options.keystore: $keypath/.keystore" -# "client_encryption_options.keystore_password: cassandra" -# "client_encryption_options.require_client_auth: true" -# "client_encryption_options.truststore: $keypath/.truststore" -# "client_encryption_options.truststore_password: cassandra" -# "concurrent_reads: 2" -# "concurrent_writes: 2" -# "write_request_timeout_in_ms: 5000" -# "read_request_timeout_in_ms: 5000" -# ) -# -# if [[ $VERSION == 3.*.* ]]; then -# conf+=( -# "rpc_server_type: sync" -# "rpc_min_threads: 2" -# "rpc_max_threads: 2" -# "enable_user_defined_functions: true" -# "enable_materialized_views: true" -# ) -# elif [[ $VERSION == 4.0.* ]]; then -# conf+=( -# "enable_user_defined_functions: true" -# "enable_materialized_views: true" -# ) -# else -# conf+=( -# "user_defined_functions_enabled: true" -# "materialized_views_enabled: true" -# ) -# fi -# -# ccm remove test || true -# -# ccm create test -v $VERSION -n 3 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" -# ccm updateconf "${conf[@]}" -# -# export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" -# -# ccm start --wait-for-binary-proto --verbose -# ccm status -# ccm node1 nodetool status -# -# args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." -# -# echo "args=$args" >> $GITHUB_ENV -# echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV -# - name: Integration tests -# run: | -# export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" -# go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} -# - name: 'Save ccm logs' -# if: 'failure()' -# uses: actions/upload-artifact@v3 -# with: -# name: ccm-cluster -# path: /home/runner/.ccm/test -# retention-days: 5 -# integration-auth-cassandra: -# timeout-minutes: 15 -# needs: -# - build -# name: Integration Tests with auth -# runs-on: ubuntu-latest -# strategy: -# fail-fast: false -# matrix: -# go: [ '1.19', '1.20' ] -# cassandra_version: [ '4.0.8' ] -# compressor: [ "snappy" ] -# tags: [ "integration" ] -# -# steps: -# - uses: actions/checkout@v3 -# - uses: actions/setup-go@v4 -# with: -# go-version: ${{ matrix.go }} -# - name: Install CCM -# run: pip install "git+https://github.com/riptano/ccm.git@${CCM_VERSION}" -# - name: Start cassandra nodes -# run: | -# VERSION=${{ matrix.cassandra_version }} -# keypath="$(pwd)/testdata/pki" -# conf=( -# "client_encryption_options.enabled: true" -# "client_encryption_options.keystore: $keypath/.keystore" -# "client_encryption_options.keystore_password: cassandra" -# "client_encryption_options.require_client_auth: true" -# "client_encryption_options.truststore: $keypath/.truststore" -# "client_encryption_options.truststore_password: cassandra" -# "concurrent_reads: 2" -# "concurrent_writes: 2" -# "write_request_timeout_in_ms: 5000" -# "read_request_timeout_in_ms: 5000" -# "authenticator: PasswordAuthenticator" -# "authorizer: CassandraAuthorizer" -# "enable_user_defined_functions: true" -# ) -# -# if [[ $VERSION == 3.*.* ]]; then -# conf+=( -# "rpc_server_type: sync" -# "rpc_min_threads: 2" -# "rpc_max_threads: 2" -# "enable_user_defined_functions: true" -# "enable_materialized_views: true" -# ) -# elif [[ $VERSION == 4.0.* ]]; then -# conf+=( -# "enable_user_defined_functions: true" -# "enable_materialized_views: true" -# ) -# else -# conf+=( -# "user_defined_functions_enabled: true" -# "materialized_views_enabled: true" -# ) -# fi -# -# ccm remove test || true -# -# ccm create test -v $VERSION -n 1 -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" -# ccm updateconf "${conf[@]}" -# -# rm -rf $HOME/.ccm/test/node1/data/system_auth -# -# export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" -# -# ccm start --wait-for-binary-proto --verbose -# ccm status -# ccm node1 nodetool status -# -# args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=$VERSION -cluster=$(ccm liveset) ./..." -# -# echo "args=$args" >> $GITHUB_ENV -# echo "JVM_EXTRA_OPTS=$JVM_EXTRA_OPTS" >> $GITHUB_ENV -# sleep 30s -# - name: Integration tests -# run: | -# export JVM_EXTRA_OPTS="${{env.JVM_EXTRA_OPTS}}" -# go test -v -run=TestAuthentication -tags "${{ matrix.tags }} gocql_debug" -timeout=15s -runauth ${{ env.args }} -# + integration-testscontainers: needs: build runs-on: ubuntu-latest - name: testcontainers-go + name: integration-testscontainers strategy: matrix: - go: [ '1.20' ] + go: [ '1.20', '1.21' ] cassandra_version: [ '4.0.8', '4.1.1' ] auth: [ "false" ] compressor: [ "snappy" ] tags: [ "cassandra", "integration"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 with: go-version: ${{ matrix.go }} - name: setup @@ -222,4 +45,26 @@ jobs: echo "args=$args" >> $GITHUB_ENV - name: run run: | - go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} + go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} + + integration-auth-testscontainers: + needs: build + runs-on: ubuntu-latest + name: integration-auth-testscontainers + strategy: + matrix: + go: [ '1.20', '1.21' ] + cassandra_version: [ '4.0.8', '4.1.1' ] + compressor: [ "snappy" ] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go }} + - name: setup + run: | + args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." + echo "args=$args" >> $GITHUB_ENV + - name: run + run: | + go test -v -run=TestAuthentication -tags integration gocql_debug -timeout=15s -runauth ${{ env.args }} diff --git a/CHANGELOG.md b/CHANGELOG.md index cf02cf0b9..8d0545fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - +- Integrated testcontainers-go as the new test runner for integration tests. ### Changed - +- Updated GitHub workflows to use `testcontainers-go` for CCM integration tests, replacing the previous CCM integration test runner. ### Fixed +- Corrected `rpc_address` to `connect_address` in the `TestDiscoverViaProxy` test case. ## [1.7.0] - 2024-09-23 diff --git a/NOTICE b/NOTICE index f4447175c..3a2acfefb 100644 --- a/NOTICE +++ b/NOTICE @@ -182,3 +182,4 @@ Dmitry Kropachev Oliver Boyle * Jackson Fleming * Sylwia Szunejko * +Stanislav Bychkov diff --git a/go.mod b/go.mod index c0fe6133a..f75b3c00a 100644 --- a/go.mod +++ b/go.mod @@ -17,26 +17,29 @@ // module github.com/gocql/gocql +go 1.21 + require ( - github.com/golang/snappy v0.0.3 + github.com/golang/snappy v0.0.4 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed - github.com/testcontainers/testcontainers-go v0.31.0 + github.com/testcontainers/testcontainers-go v0.32.0 gopkg.in/inf.v0 v0.9.1 ) require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/Microsoft/hcsshim v0.11.4 // indirect - github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/Microsoft/hcsshim v0.11.5 // indirect + github.com/bitly/go-hostpool v0.1.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/containerd/containerd v1.7.15 // indirect + github.com/containerd/containerd v1.7.18 // indirect + github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect - github.com/distribution/reference v0.5.0 // indirect - github.com/docker/docker v25.0.5+incompatible // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v27.0.3+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -44,12 +47,12 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.16.0 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/user v0.1.0 // indirect @@ -69,13 +72,9 @@ require ( go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d // indirect - google.golang.org/grpc v1.58.3 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/sys v0.21.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.33.0 // indirect ) - -go 1.21 diff --git a/go.sum b/go.sum index 9075e7dee..65a8c701a 100644 --- a/go.sum +++ b/go.sum @@ -4,18 +4,20 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= -github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Microsoft/hcsshim v0.11.5 h1:haEcLNpj9Ka1gd3B3tAEs9CpE0c+1IhoL59w/exYU38= +github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= +github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= +github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/containerd/containerd v1.7.15 h1:afEHXdil9iAm03BmhjzKyXnnEBtjaLJefdU7DV0IFes= -github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY= +github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= +github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= +github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= +github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= @@ -26,10 +28,10 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= -github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE= +github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -45,10 +47,8 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -61,8 +61,8 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= 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/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -71,6 +71,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -104,14 +106,15 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U= -github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI= +github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= +github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -139,23 +142,19 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -166,40 +165,39 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d h1:pgIUhmqwKOUlnKna4r6amKdUngdL8DrkpFeV8+VBElY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/main_test.go b/main_test.go index ce0a71d1a..c8cf5811f 100644 --- a/main_test.go +++ b/main_test.go @@ -22,6 +22,29 @@ func TestMain(m *testing.M) { flag.Parse() + cassandraVersion := flagCassVersion.String()[1:] + + jvmOpts := "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" + if *clusterSize == 1 { + // speeds up the creation of a single-node cluster. + jvmOpts += " -Dcassandra.initial_token=0 -Dcassandra.skip_wait_for_gossip_to_settle=0" + } + + env := map[string]string{ + "JVM_OPTS": jvmOpts, + "CASSANDRA_SEEDS": "cassandra1", + "CASSANDRA_DC": "datacenter1", + "HEAP_NEWSIZE": "100M", + "MAX_HEAP_SIZE": "256M", + "CASSANDRA_RACK": "rack1", + "CASSANDRA_ENDPOINT_SNITCH": "GossipingPropertyFileSnitch", + "CASS_VERSION": cassandraVersion, + } + + if *flagRunAuthTest { + env["AUTH_TEST"] = "true" + } + networkRequest := testcontainers.GenericNetworkRequest{ NetworkRequest: testcontainers.NetworkRequest{ Name: "cassandra", @@ -33,22 +56,12 @@ func TestMain(m *testing.M) { } defer cassandraNetwork.Remove(ctx) - cassandraVersion := flagCassVersion.String()[1:] // Function to create a Cassandra container (node) createCassandraContainer := func(number int) (string, error) { req := testcontainers.ContainerRequest{ Image: "cassandra:" + cassandraVersion, ExposedPorts: []string{"9042/tcp"}, - Env: map[string]string{ - "JVM_OPTS": "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler", - "CASSANDRA_SEEDS": "cassandra1", - "CASSANDRA_DC": "datacenter1", - "HEAP_NEWSIZE": "100M", - "MAX_HEAP_SIZE": "256M", - "CASSANDRA_RACK": "rack1", - "CASSANDRA_ENDPOINT_SNITCH": "GossipingPropertyFileSnitch", - "CASS_VERSION": cassandraVersion, - }, + Env: env, Files: []testcontainers.ContainerFile{ { HostFilePath: "./testdata/pki/.keystore", @@ -71,7 +84,7 @@ func TestMain(m *testing.M) { LifecycleHooks: []testcontainers.ContainerLifecycleHooks{{ PostStarts: []testcontainers.ContainerHook{ func(ctx context.Context, c testcontainers.Container) error { - // wait for cassandra config to initialize + // wait for cassandra config.yaml to initialize time.Sleep(100 * time.Millisecond) code, _, err := c.Exec(ctx, []string{"bash", "./update_container_cass_config.sh"}) @@ -120,6 +133,11 @@ func TestMain(m *testing.M) { *flagCluster += ip } + if *flagRunAuthTest { + // it requires additional time to properly build Cassandra with authentication. + time.Sleep(10 * time.Second) + } + // run all tests code := m.Run() diff --git a/update_container_cass_config.sh b/update_container_cass_config.sh index b768f2911..f9310dd40 100755 --- a/update_container_cass_config.sh +++ b/update_container_cass_config.sh @@ -69,6 +69,13 @@ configure_cassandra() { "concurrent_writes:2" ) + if [[ $AUTH_TEST == true ]]; then + conf+=( + "authenticator: PasswordAuthenticator" + "authorizer: CassandraAuthorizer" + ) + fi + if [[ $CASS_VERSION == 3.*.* ]]; then conf+=( "rpc_server_type:sync" From e7bb5c775d0885f421c13f7d46480c6dc35932eb Mon Sep 17 00:00:00 2001 From: Bychkov Date: Thu, 5 Sep 2024 09:53:47 +0300 Subject: [PATCH 03/10] ci bump to 1.23 --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d20f503ae..2d82e2576 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.20', '1.21' ] + go: [ '1.20', '1.23' ] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 @@ -29,7 +29,7 @@ jobs: name: integration-testscontainers strategy: matrix: - go: [ '1.20', '1.21' ] + go: [ '1.20', '1.23' ] cassandra_version: [ '4.0.8', '4.1.1' ] auth: [ "false" ] compressor: [ "snappy" ] @@ -53,7 +53,7 @@ jobs: name: integration-auth-testscontainers strategy: matrix: - go: [ '1.20', '1.21' ] + go: [ '1.20', '1.23' ] cassandra_version: [ '4.0.8', '4.1.1' ] compressor: [ "snappy" ] steps: @@ -67,4 +67,4 @@ jobs: echo "args=$args" >> $GITHUB_ENV - name: run run: | - go test -v -run=TestAuthentication -tags integration gocql_debug -timeout=15s -runauth ${{ env.args }} + go test -v -run=TestAuthentication -tags ""integration" gocql_debug" -timeout=15s -runauth ${{ env.args }} From 2cae706bad51ce6ebe13967ecd7d76ec0d8132d3 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Thu, 22 Aug 2024 12:35:04 +0300 Subject: [PATCH 04/10] fix flaky tests --- .github/workflows/main.yml | 10 +- cassandra_test.go | 1 - control_ccm_test.go | 73 +++----- events_ccm_test.go | 222 ++++++++--------------- go.mod | 19 +- go.sum | 38 ++-- main_test.go | 303 +++++++++++++++++++++++--------- testdata/pki/cqlshrc | 13 ++ update_container_cass_config.sh | 17 +- 9 files changed, 370 insertions(+), 326 deletions(-) create mode 100644 testdata/pki/cqlshrc diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2d82e2576..ae66bfbe5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.20', '1.23' ] + go: [ '1.22', '1.23' ] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 @@ -29,11 +29,11 @@ jobs: name: integration-testscontainers strategy: matrix: - go: [ '1.20', '1.23' ] + go: [ '1.22', '1.23' ] cassandra_version: [ '4.0.8', '4.1.1' ] auth: [ "false" ] compressor: [ "snappy" ] - tags: [ "cassandra", "integration"] + tags: [ "cassandra", "integration", "tc"] steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 @@ -45,7 +45,7 @@ jobs: echo "args=$args" >> $GITHUB_ENV - name: run run: | - go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=5m -race ${{ env.args }} + go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=10m -race ${{ env.args }} integration-auth-testscontainers: needs: build @@ -53,7 +53,7 @@ jobs: name: integration-auth-testscontainers strategy: matrix: - go: [ '1.20', '1.23' ] + go: [ '1.22', '1.23' ] cassandra_version: [ '4.0.8', '4.1.1' ] compressor: [ "snappy" ] steps: diff --git a/cassandra_test.go b/cassandra_test.go index 9401eb1e6..9a4fe0609 100644 --- a/cassandra_test.go +++ b/cassandra_test.go @@ -628,7 +628,6 @@ func TestBatch(t *testing.T) { } func TestUnpreparedBatch(t *testing.T) { - t.Skip("FLAKE skipping") session := createSession(t) defer session.Close() diff --git a/control_ccm_test.go b/control_ccm_test.go index 426a59aef..48f5362e5 100644 --- a/control_ccm_test.go +++ b/control_ccm_test.go @@ -1,5 +1,5 @@ -//go:build ccm -// +build ccm +//go:build tc +// +build tc /* * Licensed to the Apache Software Foundation (ASF) under one @@ -28,17 +28,16 @@ package gocql import ( + "context" "fmt" "sync" "testing" "time" - - "github.com/gocql/gocql/internal/ccm" ) type TestHostFilter struct { mu sync.Mutex - allowedHosts map[string]ccm.Host + allowedHosts map[string]TChost } func (f *TestHostFilter) Accept(h *HostInfo) bool { @@ -48,37 +47,27 @@ func (f *TestHostFilter) Accept(h *HostInfo) bool { return ok } -func (f *TestHostFilter) SetAllowedHosts(hosts map[string]ccm.Host) { +func (f *TestHostFilter) SetAllowedHosts(hosts map[string]TChost) { f.mu.Lock() defer f.mu.Unlock() f.allowedHosts = hosts } func TestControlConn_ReconnectRefreshesRing(t *testing.T) { - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } - - allCcmHosts, err := ccm.Status() - if err != nil { - t.Fatal(err) - } + ctx := context.Background() - if len(allCcmHosts) < 2 { + if len(cassNodes) < 2 { t.Skip("this test requires at least 2 nodes") } - allAllowedHosts := map[string]ccm.Host{} - var firstNode *ccm.Host - for _, node := range allCcmHosts { - if firstNode == nil { - firstNode = &node - } + allAllowedHosts := map[string]TChost{} + for _, node := range cassNodes { allAllowedHosts[node.Addr] = node } - allowedHosts := map[string]ccm.Host{ - firstNode.Addr: *firstNode, + firstNode := cassNodes["node1"] + allowedHosts := map[string]TChost{ + firstNode.Addr: firstNode, } testFilter := &TestHostFilter{allowedHosts: allowedHosts} @@ -99,9 +88,9 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { ccHost := controlConnection.host var ccHostName string - for _, node := range allCcmHosts { + for name, node := range cassNodes { if node.Addr == ccHost.ConnectAddress().String() { - ccHostName = node.Name + ccHostName = name break } } @@ -110,25 +99,15 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { t.Fatal("could not find name of control host") } - if err := ccm.NodeDown(ccHostName); err != nil { + if err := cassNodes[ccHostName].TC.Stop(ctx, nil); err != nil { t.Fatal() } - defer func() { - ccmStatus, err := ccm.Status() - if err != nil { - t.Logf("could not bring nodes back up after test: %v", err) - return - } - for _, node := range ccmStatus { - if node.State == ccm.NodeStateDown { - err = ccm.NodeUp(node.Name) - if err != nil { - t.Logf("could not bring node %v back up after test: %v", node.Name, err) - } - } + defer func(ctx context.Context) { + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't restore a cluster : %v", err) } - }() + }(ctx) assertNodeDown := func() error { hosts := session.ring.currentHosts() @@ -159,19 +138,19 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { } if assertErr != nil { - t.Fatal(err) + t.Fatal(assertErr) } testFilter.SetAllowedHosts(allAllowedHosts) - if err = ccm.NodeUp(ccHostName); err != nil { + if err := restoreCluster(ctx); err != nil { t.Fatal(err) } assertNodeUp := func() error { hosts := session.ring.currentHosts() - if len(hosts) != len(allCcmHosts) { - return fmt.Errorf("expected %v hosts in ring but there were %v", len(allCcmHosts), len(hosts)) + if len(hosts) != len(cassNodes) { + return fmt.Errorf("expected %v hosts in ring but there were %v", len(ccHostName), len(hosts)) } for _, host := range hosts { if !host.IsUp() { @@ -181,8 +160,8 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { session.pool.mu.RLock() poolsLen := len(session.pool.hostConnPools) session.pool.mu.RUnlock() - if poolsLen != len(allCcmHosts) { - return fmt.Errorf("expected %v connection pool but there were %v", len(allCcmHosts), poolsLen) + if poolsLen != len(cassNodes) { + return fmt.Errorf("expected %v connection pool but there were %v", len(ccHostName), poolsLen) } return nil } @@ -196,6 +175,6 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { } if assertErr != nil { - t.Fatal(err) + t.Fatal(assertErr) } } diff --git a/events_ccm_test.go b/events_ccm_test.go index a105985bc..e84168722 100644 --- a/events_ccm_test.go +++ b/events_ccm_test.go @@ -1,5 +1,5 @@ -//go:build (ccm && ignore) || ignore -// +build ccm,ignore ignore +//go:build tc +// +build tc /* * Licensed to the Apache Software Foundation (ASF) under one @@ -28,83 +28,52 @@ package gocql import ( - "log" + "context" "testing" "time" - - "github.com/gocql/gocql/internal/ccm" ) func TestEventDiscovery(t *testing.T) { - t.Skip("FLAKE skipping") - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } - session := createSession(t) defer session.Close() - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } - t.Logf("status=%+v\n", status) - - session.pool.mu.RLock() - poolHosts := session.pool.hostConnPools // TODO: replace with session.ring - t.Logf("poolhosts=%+v\n", poolHosts) // check we discovered all the nodes in the ring - for _, host := range status { - if _, ok := poolHosts[host.Addr]; !ok { - t.Errorf("did not discover %q", host.Addr) + for _, node := range cassNodes { + host := session.ring.getHost(node.ID) + if host == nil { + t.Errorf("did not discover %q", node.Addr) + } + if t.Failed() { + t.FailNow() } - } - session.pool.mu.RUnlock() - if t.Failed() { - t.FailNow() } } func TestEventNodeDownControl(t *testing.T) { - t.Skip("FLAKE skipping") + ctx := context.Background() const targetNode = "node1" - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } - - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } + node := cassNodes[targetNode] cluster := createCluster() - cluster.Hosts = []string{status[targetNode].Addr} + cluster.Hosts = []string{node.Addr} session := createSessionFromCluster(cluster, t) defer session.Close() - t.Log("marking " + targetNode + " as down") - if err := ccm.NodeDown(targetNode); err != nil { + t.Logf("marking node %q down \n", targetNode) + if err := node.TC.Stop(ctx, nil); err != nil { t.Fatal(err) } + defer func(ctx context.Context) { + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't restore a cluster : %v", err) + } + }(ctx) - t.Logf("status=%+v\n", status) - t.Logf("marking node %q down: %v\n", targetNode, status[targetNode]) - - time.Sleep(5 * time.Second) - - session.pool.mu.RLock() - - poolHosts := session.pool.hostConnPools - node := status[targetNode] - t.Logf("poolhosts=%+v\n", poolHosts) - - if _, ok := poolHosts[node.Addr]; ok { - session.pool.mu.RUnlock() + if _, ok := getPool(session.pool, node.ID); ok { t.Fatal("node not removed after remove event") } - session.pool.mu.RUnlock() - host := session.ring.getHost(node.Addr) + host := session.ring.getHost(node.ID) if host == nil { t.Fatal("node not in metadata ring") } else if host.IsUp() { @@ -113,40 +82,28 @@ func TestEventNodeDownControl(t *testing.T) { } func TestEventNodeDown(t *testing.T) { - t.Skip("FLAKE skipping") + ctx := context.Background() + const targetNode = "node3" - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } + node := cassNodes[targetNode] session := createSession(t) defer session.Close() - if err := ccm.NodeDown(targetNode); err != nil { + if err := node.TC.Stop(ctx, nil); err != nil { t.Fatal(err) } + defer func(ctx context.Context) { + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't restore a cluster : %v", err) + } + }(ctx) - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } - t.Logf("status=%+v\n", status) - t.Logf("marking node %q down: %v\n", targetNode, status[targetNode]) - - time.Sleep(5 * time.Second) - - session.pool.mu.RLock() - defer session.pool.mu.RUnlock() - - poolHosts := session.pool.hostConnPools - node := status[targetNode] - t.Logf("poolhosts=%+v\n", poolHosts) - - if _, ok := poolHosts[node.Addr]; ok { - t.Fatal("node not removed after remove event") + if _, ok := getPool(session.pool, node.ID); ok { + t.Errorf("node not removed after remove event") } - host := session.ring.getHost(node.Addr) + host := session.ring.getHost(node.ID) if host == nil { t.Fatal("node not in metadata ring") } else if host.IsUp() { @@ -155,55 +112,39 @@ func TestEventNodeDown(t *testing.T) { } func TestEventNodeUp(t *testing.T) { - t.Skip("FLAKE skipping") - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } - - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } - log.Printf("status=%+v\n", status) + ctx := context.Background() session := createSession(t) defer session.Close() const targetNode = "node2" - node := status[targetNode] + node := cassNodes[targetNode] - _, ok := session.pool.getPool(node.Addr) - if !ok { - session.pool.mu.RLock() - t.Errorf("target pool not in connection pool: addr=%q pools=%v", status[targetNode].Addr, session.pool.hostConnPools) - session.pool.mu.RUnlock() + if _, ok := getPool(session.pool, node.ID); !ok { + t.Errorf("target pool not in connection pool: addr=%q pools=%v", node.Addr, session.pool.hostConnPools) t.FailNow() } - if err := ccm.NodeDown(targetNode); err != nil { + if err := node.TC.Stop(ctx, nil); err != nil { t.Fatal(err) } - time.Sleep(5 * time.Second) - - _, ok = session.pool.getPool(node.Addr) - if ok { + if _, ok := getPool(session.pool, node.ID); ok { t.Fatal("node not removed after remove event") } - if err := ccm.NodeUp(targetNode); err != nil { - t.Fatal(err) + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't restore a cluster : %v", err) } // cassandra < 2.2 needs 10 seconds to start up the binary service time.Sleep(15 * time.Second) - _, ok = session.pool.getPool(node.Addr) - if !ok { + if _, ok := getPool(session.pool, node.ID); !ok { t.Fatal("node not added after node added event") } - host := session.ring.getHost(node.Addr) + host := session.ring.getHost(node.ID) if host == nil { t.Fatal("node not in metadata ring") } else if !host.IsUp() { @@ -212,29 +153,23 @@ func TestEventNodeUp(t *testing.T) { } func TestEventFilter(t *testing.T) { - t.Skip("FLAKE skipping") - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } - - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } - log.Printf("status=%+v\n", status) + ctx := context.Background() cluster := createCluster() - cluster.HostFilter = WhiteListHostFilter(status["node1"].Addr) + + whiteListedNodeName := "node1" + whiteListedNode := cassNodes[whiteListedNodeName] + cluster.HostFilter = WhiteListHostFilter(whiteListedNode.Addr) + session := createSessionFromCluster(cluster, t) defer session.Close() - if _, ok := session.pool.getPool(status["node1"].Addr); !ok { - t.Errorf("should have %v in pool but dont", "node1") + if _, ok := getPool(session.pool, whiteListedNode.ID); !ok { + t.Errorf("should have %v in pool but dont", whiteListedNodeName) } for _, host := range [...]string{"node2", "node3"} { - _, ok := session.pool.getPool(status[host].Addr) - if ok { + if _, ok := getPool(session.pool, cassNodes[host].ID); ok { t.Errorf("should not have %v in pool", host) } } @@ -243,19 +178,18 @@ func TestEventFilter(t *testing.T) { t.FailNow() } - if err := ccm.NodeDown("node2"); err != nil { + shutdownNode := cassNodes["node2"] + + if err := shutdownNode.TC.Stop(ctx, nil); err != nil { t.Fatal(err) } - time.Sleep(5 * time.Second) - - if err := ccm.NodeUp("node2"); err != nil { - t.Fatal(err) + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't restore a cluster : %v", err) } - time.Sleep(15 * time.Second) for _, host := range [...]string{"node2", "node3"} { - _, ok := session.pool.getPool(status[host].Addr) + _, ok := getPool(session.pool, cassNodes[host].ID) if ok { t.Errorf("should not have %v in pool", host) } @@ -264,51 +198,35 @@ func TestEventFilter(t *testing.T) { if t.Failed() { t.FailNow() } - } func TestEventDownQueryable(t *testing.T) { - t.Skip("FLAKE skipping") - if err := ccm.AllUp(); err != nil { - t.Fatal(err) - } + ctx := context.Background() - status, err := ccm.Status() - if err != nil { - t.Fatal(err) - } - log.Printf("status=%+v\n", status) - - const targetNode = "node1" - - addr := status[targetNode].Addr + targetNode := cassNodes["node1"] cluster := createCluster() - cluster.Hosts = []string{addr} - cluster.HostFilter = WhiteListHostFilter(addr) + cluster.Hosts = []string{targetNode.Addr} + cluster.HostFilter = WhiteListHostFilter(targetNode.Addr) session := createSessionFromCluster(cluster, t) defer session.Close() - if pool, ok := session.pool.getPool(addr); !ok { - t.Fatalf("should have %v in pool but dont", addr) + if pool, ok := getPool(session.pool, targetNode.ID); !ok { + t.Fatalf("should have %v in pool but dont", targetNode.Addr) } else if !pool.host.IsUp() { t.Fatalf("host is not up %v", pool.host) } - if err := ccm.NodeDown(targetNode); err != nil { + if err := targetNode.TC.Stop(ctx, nil); err != nil { t.Fatal(err) } - time.Sleep(5 * time.Second) - - if err := ccm.NodeUp(targetNode); err != nil { - t.Fatal(err) + if err := restoreCluster(ctx); err != nil { + t.Fatalf("couldn't preserve a cluster : %v", err) } - time.Sleep(15 * time.Second) - - if pool, ok := session.pool.getPool(addr); !ok { - t.Fatalf("should have %v in pool but dont", addr) + if pool, ok := getPool(session.pool, targetNode.ID); !ok { + t.Fatalf("should have %v in pool but dont", targetNode.Addr) } else if !pool.host.IsUp() { t.Fatalf("host is not up %v", pool.host) } diff --git a/go.mod b/go.mod index f75b3c00a..53ab9193e 100644 --- a/go.mod +++ b/go.mod @@ -17,12 +17,12 @@ // module github.com/gocql/gocql -go 1.21 +go 1.23 require ( github.com/golang/snappy v0.0.4 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed - github.com/testcontainers/testcontainers-go v0.32.0 + github.com/testcontainers/testcontainers-go v0.33.0 gopkg.in/inf.v0 v0.9.1 ) @@ -30,16 +30,13 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Microsoft/hcsshim v0.11.5 // indirect - github.com/bitly/go-hostpool v0.1.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/containerd/containerd v1.7.18 // indirect - github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v27.0.3+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -72,9 +69,11 @@ require ( go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/sys v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.64.1 // indirect - google.golang.org/protobuf v1.33.0 // indirect +) + +require ( + github.com/bitly/go-hostpool v0.1.0 // indirect + github.com/docker/docker v27.1.1+incompatible ) diff --git a/go.sum b/go.sum index 65a8c701a..9f0781765 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.11.5 h1:haEcLNpj9Ka1gd3B3tAEs9CpE0c+1IhoL59w/exYU38= -github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= @@ -16,10 +14,10 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= -github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= -github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -30,8 +28,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE= -github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -113,8 +111,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= -github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -142,16 +140,16 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -167,12 +165,12 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -184,10 +182,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= +google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= diff --git a/main_test.go b/main_test.go index c8cf5811f..78223a2a4 100644 --- a/main_test.go +++ b/main_test.go @@ -1,5 +1,29 @@ -//go:build cassandra || integration -// +build cassandra integration +//go:build cassandra || integration || tc +// +build cassandra integration tc + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 + * Copyright (c) 2016, The Gocql authors, + * provided under the BSD-3-Clause License. + * See the NOTICE file distributed with this work for additional information. + */ package gocql @@ -7,21 +31,57 @@ import ( "context" "flag" "fmt" + "io" "log" "os" "strconv" + "strings" "testing" "time" "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/network" "github.com/testcontainers/testcontainers-go/wait" ) +type TChost struct { + TC testcontainers.Container + Addr string + ID string +} + +var cassNodes = make(map[string]TChost) +var networkName string + func TestMain(m *testing.M) { ctx := context.Background() flag.Parse() + net, err := network.New(ctx) + if err != nil { + log.Fatal("cannot create network: ", err) + } + networkName = net.Name + + //collect cass nodes into a cluster + *flagCluster = "" + for i := 1; i <= *clusterSize; i++ { + err = NodeUpTC(ctx, i) + if err != nil { + log.Fatalf("Failed to start Cassandra node %d: %v", i, err) + } + } + // remove the last coma + *flagCluster = (*flagCluster)[:len(*flagCluster)-1] + + // run all tests + code := m.Run() + + os.Exit(code) +} + +func NodeUpTC(ctx context.Context, number int) error { cassandraVersion := flagCassVersion.String()[1:] jvmOpts := "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" @@ -32,7 +92,7 @@ func TestMain(m *testing.M) { env := map[string]string{ "JVM_OPTS": jvmOpts, - "CASSANDRA_SEEDS": "cassandra1", + "CASSANDRA_SEEDS": "node1", "CASSANDRA_DC": "datacenter1", "HEAP_NEWSIZE": "100M", "MAX_HEAP_SIZE": "256M", @@ -45,92 +105,88 @@ func TestMain(m *testing.M) { env["AUTH_TEST"] = "true" } - networkRequest := testcontainers.GenericNetworkRequest{ - NetworkRequest: testcontainers.NetworkRequest{ - Name: "cassandra", - }, - } - cassandraNetwork, err := testcontainers.GenericNetwork(ctx, networkRequest) - if err != nil { - log.Fatalf("Failed to create network: %s", err) - } - defer cassandraNetwork.Remove(ctx) - - // Function to create a Cassandra container (node) - createCassandraContainer := func(number int) (string, error) { - req := testcontainers.ContainerRequest{ - Image: "cassandra:" + cassandraVersion, - ExposedPorts: []string{"9042/tcp"}, - Env: env, - Files: []testcontainers.ContainerFile{ - { - HostFilePath: "./testdata/pki/.keystore", - ContainerFilePath: "testdata/.keystore", - FileMode: 0o777, - }, - { - HostFilePath: "./testdata/pki/.truststore", - ContainerFilePath: "testdata/.truststore", - FileMode: 0o777, - }, - { - HostFilePath: "update_container_cass_config.sh", - ContainerFilePath: "/update_container_cass_config.sh", - FileMode: 0o777, - }, + fs := []testcontainers.ContainerFile{{}} + if *flagRunSslTest { + env["RUN_SSL_TEST"] = "true" + fs = []testcontainers.ContainerFile{ + { + HostFilePath: "./testdata/pki/.keystore", + ContainerFilePath: "testdata/.keystore", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/.truststore", + ContainerFilePath: "testdata/.truststore", + FileMode: 0o777, + }, + { + HostFilePath: "update_container_cass_config.sh", + ContainerFilePath: "/update_container_cass_config.sh", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/cqlshrc", + ContainerFilePath: "/root/.cassandra/cqlshrc", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/gocql.crt", + ContainerFilePath: "/root/.cassandra/gocql.crt", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/gocql.key", + ContainerFilePath: "/root/.cassandra/gocql.key", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/pki/ca.crt", + ContainerFilePath: "/root/.cassandra/ca.crt", + FileMode: 0o777, }, - - Networks: []string{"cassandra"}, - LifecycleHooks: []testcontainers.ContainerLifecycleHooks{{ - PostStarts: []testcontainers.ContainerHook{ - func(ctx context.Context, c testcontainers.Container) error { - // wait for cassandra config.yaml to initialize - time.Sleep(100 * time.Millisecond) - - code, _, err := c.Exec(ctx, []string{"bash", "./update_container_cass_config.sh"}) - if err != nil { - return err - } - if code != 0 { - return fmt.Errorf("script ./update_container_cass_config.sh exited with code %d", code) - } - return nil - }, - }, - }}, - WaitingFor: wait.ForLog("Startup complete").WithStartupTimeout(2 * time.Minute), - Name: "cassandra" + strconv.Itoa(number), - } - container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: req, - Started: true, - }) - if err != nil { - return "", err } + } - ip, err := container.ContainerIP(ctx) - if err != nil { - return "", err - } + req := testcontainers.ContainerRequest{ + Image: "cassandra:" + cassandraVersion, + Env: env, + Files: fs, + Networks: []string{networkName}, + LifecycleHooks: []testcontainers.ContainerLifecycleHooks{{ + PostStarts: []testcontainers.ContainerHook{ + func(ctx context.Context, c testcontainers.Container) error { + // wait for cassandra config.yaml to initialize + time.Sleep(100 * time.Millisecond) - return ip, nil - } + _, body, err := c.Exec(ctx, []string{"bash", "./update_container_cass_config.sh"}) + if err != nil { + return err + } - // collect cass nodes into a cluster - *flagCluster = "" - for i := 0; i < *clusterSize; i++ { - ip, err := createCassandraContainer(i + 1) - if err != nil { - log.Fatalf("Failed to start Cassandra node %d: %v", i+1, err) - } + data, _ := io.ReadAll(body) + if ok := strings.Contains(string(data), "Cassandra configuration modified successfully."); !ok { + return fmt.Errorf("./update_container_cass_config.sh didn't complete successfully %v", string(data)) + } - // if not the last iteration - if i != *clusterSize-1 { - ip += "," - } + return nil + }, + }, + }}, + WaitingFor: wait.ForLog("Startup complete").WithStartupTimeout(2 * time.Minute), + Name: "node" + strconv.Itoa(number), + } + + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return err + } - *flagCluster += ip + cIP, err := container.ContainerIP(ctx) + if err != nil { + return err } if *flagRunAuthTest { @@ -138,8 +194,85 @@ func TestMain(m *testing.M) { time.Sleep(10 * time.Second) } - // run all tests - code := m.Run() + hostID, err := getCassNodeID(ctx, container, cIP) + if err != nil { + return err + } - os.Exit(code) + cassNodes[req.Name] = TChost{ + TC: container, + Addr: cIP, + ID: hostID, + } + + *flagCluster += cIP + "," + + return nil +} + +func getCassNodeID(ctx context.Context, container testcontainers.Container, ip string) (string, error) { + var cmd []string + if *flagRunSslTest { + cmd = []string{"cqlsh", ip, "9042", "--ssl", "ip", "/root/.cassandra/cqlshrc", "-e", "SELECT host_id FROM system.local;"} + } else { + cmd = []string{"cqlsh", "-e", "SELECT host_id FROM system.local;"} + } + + _, reader, err := container.Exec(ctx, cmd) + if err != nil { + return "", fmt.Errorf("failed to execute cqlsh command: %v", err) + } + b, err := io.ReadAll(reader) + if err != nil { + return "", err + } + output := string(b) + + lines := strings.Split(output, "\n") + + if len(lines) < 4 { + return "", fmt.Errorf("unexpected output format, less than 4 lines: %v", lines) + } + hostID := strings.TrimSpace(lines[3]) + + return hostID, nil +} + +// restoreCluster is a helper function that ensures the cluster remains fully operational during topology changes. +// Commonly used in test scenarios where nodes are added, removed, or modified to maintain cluster stability and prevent downtime. +func restoreCluster(ctx context.Context) error { + var cmd []string + for _, container := range cassNodes { + if running := container.TC.IsRunning(); running { + continue + } + if err := container.TC.Start(ctx); err != nil { + return fmt.Errorf("cannot start a container: %v", err) + } + + if *flagRunSslTest { + cmd = []string{"cqlsh", container.Addr, "9042", "--ssl", "ip", "/root/.cassandra/cqlshrc", "-e", "SELECT bootstrapped FROM system.local"} + } else { + cmd = []string{"cqlsh", "-e", "SELECT bootstrapped FROM system.local"} + } + + err := wait.ForExec(cmd).WithResponseMatcher(func(body io.Reader) bool { + data, _ := io.ReadAll(body) + return strings.Contains(string(data), "COMPLETED") + }).WaitUntilReady(ctx, container.TC) + if err != nil { + return fmt.Errorf("cannot wait until fully bootstrapped: %v", err) + } + time.Sleep(5 * time.Second) + } + + return nil +} + +// getPool is a test helper designed to enhance readability by mocking the `func (p *policyConnPool) getPool(host *HostInfo) (pool *hostConnPool, ok bool)` method. +func getPool(p *policyConnPool, hostID string) (pool *hostConnPool, ok bool) { + p.mu.RLock() + pool, ok = p.hostConnPools[hostID] + p.mu.RUnlock() + return } diff --git a/testdata/pki/cqlshrc b/testdata/pki/cqlshrc new file mode 100644 index 000000000..9939dda67 --- /dev/null +++ b/testdata/pki/cqlshrc @@ -0,0 +1,13 @@ +[ssl] +certfile = /root/.cassandra/gocql.crt +userkey = /root/.cassandra/gocql.key +usercert = /root/.cassandra/gocql.crt +ca_certs = /root/.cassandra/ca.crt +validate = false + +[connection] +factory = cqlshlib.ssl.ssl_transport_factory + +[authentication] +username = cassandra +password = cassandra diff --git a/update_container_cass_config.sh b/update_container_cass_config.sh index f9310dd40..c3bcf0611 100755 --- a/update_container_cass_config.sh +++ b/update_container_cass_config.sh @@ -59,12 +59,6 @@ update_property() { configure_cassandra() { local keypath="testdata" local conf=( - "client_encryption_options.enabled:true" - "client_encryption_options.keystore:$keypath/.keystore" - "client_encryption_options.keystore_password:cassandra" - "client_encryption_options.require_client_auth:true" - "client_encryption_options.truststore:$keypath/.truststore" - "client_encryption_options.truststore_password:cassandra" "concurrent_reads:2" "concurrent_writes:2" ) @@ -76,6 +70,17 @@ configure_cassandra() { ) fi + if [[ $RUN_SSL_TEST == true ]]; then + conf+=( + "client_encryption_options.enabled:true" + "client_encryption_options.keystore:$keypath/.keystore" + "client_encryption_options.keystore_password:cassandra" + "client_encryption_options.require_client_auth:true" + "client_encryption_options.truststore:$keypath/.truststore" + "client_encryption_options.truststore_password:cassandra" + ) + fi + if [[ $CASS_VERSION == 3.*.* ]]; then conf+=( "rpc_server_type:sync" From a20211eabdd54de2e441e3be17330a018aa73211 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Mon, 16 Sep 2024 11:05:09 +0300 Subject: [PATCH 05/10] doc: running integration tests locally --- CONTRIBUTING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0231b063c..ef4b0942f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,6 +21,23 @@ The following is a check list of requirements that need to be satisfied in order * The merge commit passes the regression test suite on GitHub Actions * `go fmt` has been applied to the submitted code * Notable changes (i.e. new features or changed behavior, bugfixes) are appropriately documented in CHANGELOG.md, functional changes also in godoc +* Before a Pull Request or a new commit, ensure that all tests pass successfully. You can run all tests locally using the following command (this process takes approximately 15 minutes): +``` +go test -v -tags "integration cassandra tc gocql_debug" -timeout=20m -race -gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=snappy -gocql.cversion=4.0.8 ./... +``` +and +``` +go test -v -run=TestAuthentication -tags ""integration" gocql_debug" -timeout=2m -runauth -gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=snappy -gocql.cversion=4.0.8 +``` +### ℹ️ **Note:** + +> The main_test.go file serves as the entry point for integration tests. It sets up an actual Cassandra cluster, sharing resources before tests are run and cleaning them up afterward, ensuring a consistent and efficient testing environment. The cluster is created locally, so you will need Docker installed. +> +> +> The setup supports both single-node (quick setup in seconds) and multi-node Cassandra clusters (approx. 5 minutes, configurable via the `-clusterSize` flag). If you're curious to try integration tests, feel free to run them yourself. Just ensure that your tests are tagged correctly (e.g., `integration`), since `main_test.go` skips unit tests for performance reasons (no need to start a cluster for unit tests) +> +> You can find examples of running integration tests in the "Before a Pull Request" section. +> * A correctly formatted commit message, see below If there are any requirements that can't be reasonably satisfied, please state this either on the pull request or as part of discussion on the mailing list. Where appropriate, the core team may apply discretion and make an exception to these requirements. From 0fb98c459d930401198b62f579b02f63b2f4ce79 Mon Sep 17 00:00:00 2001 From: Stanislav Bychkov <74422582+ribaraka@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:43:57 +0300 Subject: [PATCH 06/10] adding cass 5.0.0 --- .github/workflows/main.yml | 18 +- cassandra_test.go | 8 +- control_ccm_test.go | 8 +- events_ccm_test.go | 36 ++-- go.mod | 7 +- main_test.go | 164 +++++++----------- testdata/docker-entrypoint.sh | 97 +++++++++++ testdata/pki/cqlshrc | 13 -- .../update_cas_config.sh | 29 ++-- 9 files changed, 214 insertions(+), 166 deletions(-) create mode 100644 testdata/docker-entrypoint.sh delete mode 100644 testdata/pki/cqlshrc rename update_container_cass_config.sh => testdata/update_cas_config.sh (83%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ae66bfbe5..125701204 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,14 +23,14 @@ jobs: - name: Run unit tests run: go test -v -tags unit -race - integration-testscontainers: + integration-tc: needs: build runs-on: ubuntu-latest - name: integration-testscontainers + name: integration-tc strategy: matrix: go: [ '1.22', '1.23' ] - cassandra_version: [ '4.0.8', '4.1.1' ] + cassandra_version: [ '4.0.13', '4.1.6', '5.0.0'] auth: [ "false" ] compressor: [ "snappy" ] tags: [ "cassandra", "integration", "tc"] @@ -41,20 +41,21 @@ jobs: go-version: ${{ matrix.go }} - name: setup run: | - args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." + # todo: back the -runssl flag, as soon as the certs get updated. + args="-gocql.timeout=60s -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." echo "args=$args" >> $GITHUB_ENV - name: run run: | go test -v -tags "${{ matrix.tags }} gocql_debug" -timeout=10m -race ${{ env.args }} - integration-auth-testscontainers: + integration-auth-tc: needs: build runs-on: ubuntu-latest - name: integration-auth-testscontainers + name: integration-auth-tc strategy: matrix: go: [ '1.22', '1.23' ] - cassandra_version: [ '4.0.8', '4.1.1' ] + cassandra_version: ['4.1.6', '5.0.0' ] compressor: [ "snappy" ] steps: - uses: actions/checkout@v3 @@ -63,7 +64,8 @@ jobs: go-version: ${{ matrix.go }} - name: setup run: | - args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." + # todo: return back the -runssl flag, as soon as the certs get updated. + args="-gocql.timeout=60s -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }}" echo "args=$args" >> $GITHUB_ENV - name: run run: | diff --git a/cassandra_test.go b/cassandra_test.go index 9a4fe0609..30331ff5c 100644 --- a/cassandra_test.go +++ b/cassandra_test.go @@ -479,15 +479,15 @@ func TestCAS(t *testing.T) { } insertBatch := session.NewBatch(LoggedBatch) - insertBatch.Query("INSERT INTO cas_table (title, revid, last_modified) VALUES ('_foo', 2c3af400-73a4-11e5-9381-29463d90c3f0, DATEOF(NOW()))") - insertBatch.Query("INSERT INTO cas_table (title, revid, last_modified) VALUES ('_foo', 3e4ad2f1-73a4-11e5-9381-29463d90c3f0, DATEOF(NOW()))") + insertBatch.Query("INSERT INTO cas_table (title, revid, last_modified) VALUES ('_foo', 2c3af400-73a4-11e5-9381-29463d90c3f0, toTimestamp(NOW()))") + insertBatch.Query("INSERT INTO cas_table (title, revid, last_modified) VALUES ('_foo', 3e4ad2f1-73a4-11e5-9381-29463d90c3f0, toTimestamp(NOW()))") if err := session.ExecuteBatch(insertBatch); err != nil { t.Fatal("insert:", err) } failBatch = session.NewBatch(LoggedBatch) - failBatch.Query("UPDATE cas_table SET last_modified = DATEOF(NOW()) WHERE title='_foo' AND revid=2c3af400-73a4-11e5-9381-29463d90c3f0 IF last_modified=DATEOF(NOW());") - failBatch.Query("UPDATE cas_table SET last_modified = DATEOF(NOW()) WHERE title='_foo' AND revid=3e4ad2f1-73a4-11e5-9381-29463d90c3f0 IF last_modified=DATEOF(NOW());") + failBatch.Query("UPDATE cas_table SET last_modified = toTimestamp(NOW()) WHERE title='_foo' AND revid=2c3af400-73a4-11e5-9381-29463d90c3f0 IF last_modified=toTimestamp(NOW());") + failBatch.Query("UPDATE cas_table SET last_modified = toTimestamp(NOW()) WHERE title='_foo' AND revid=3e4ad2f1-73a4-11e5-9381-29463d90c3f0 IF last_modified=toTimestamp(NOW());") if applied, iter, err := session.ExecuteBatchCAS(failBatch, &titleCAS, &revidCAS, &modifiedCAS); err != nil { t.Fatal("insert:", err) } else if applied { diff --git a/control_ccm_test.go b/control_ccm_test.go index 48f5362e5..53a0c3644 100644 --- a/control_ccm_test.go +++ b/control_ccm_test.go @@ -37,7 +37,7 @@ import ( type TestHostFilter struct { mu sync.Mutex - allowedHosts map[string]TChost + allowedHosts map[string]*tcNode } func (f *TestHostFilter) Accept(h *HostInfo) bool { @@ -47,7 +47,7 @@ func (f *TestHostFilter) Accept(h *HostInfo) bool { return ok } -func (f *TestHostFilter) SetAllowedHosts(hosts map[string]TChost) { +func (f *TestHostFilter) SetAllowedHosts(hosts map[string]*tcNode) { f.mu.Lock() defer f.mu.Unlock() f.allowedHosts = hosts @@ -60,13 +60,13 @@ func TestControlConn_ReconnectRefreshesRing(t *testing.T) { t.Skip("this test requires at least 2 nodes") } - allAllowedHosts := map[string]TChost{} + allAllowedHosts := map[string]*tcNode{} for _, node := range cassNodes { allAllowedHosts[node.Addr] = node } firstNode := cassNodes["node1"] - allowedHosts := map[string]TChost{ + allowedHosts := map[string]*tcNode{ firstNode.Addr: firstNode, } diff --git a/events_ccm_test.go b/events_ccm_test.go index e84168722..b1f56182e 100644 --- a/events_ccm_test.go +++ b/events_ccm_test.go @@ -39,7 +39,7 @@ func TestEventDiscovery(t *testing.T) { // check we discovered all the nodes in the ring for _, node := range cassNodes { - host := session.ring.getHost(node.ID) + host := session.ring.getHost(node.HostID) if host == nil { t.Errorf("did not discover %q", node.Addr) } @@ -69,11 +69,11 @@ func TestEventNodeDownControl(t *testing.T) { } }(ctx) - if _, ok := getPool(session.pool, node.ID); ok { + if _, ok := getPool(session.pool, node.HostID); ok { t.Fatal("node not removed after remove event") } - host := session.ring.getHost(node.ID) + host := session.ring.getHost(node.HostID) if host == nil { t.Fatal("node not in metadata ring") } else if host.IsUp() { @@ -99,11 +99,11 @@ func TestEventNodeDown(t *testing.T) { } }(ctx) - if _, ok := getPool(session.pool, node.ID); ok { + if _, ok := getPool(session.pool, node.HostID); ok { t.Errorf("node not removed after remove event") } - host := session.ring.getHost(node.ID) + host := session.ring.getHost(node.HostID) if host == nil { t.Fatal("node not in metadata ring") } else if host.IsUp() { @@ -120,7 +120,7 @@ func TestEventNodeUp(t *testing.T) { const targetNode = "node2" node := cassNodes[targetNode] - if _, ok := getPool(session.pool, node.ID); !ok { + if _, ok := getPool(session.pool, node.HostID); !ok { t.Errorf("target pool not in connection pool: addr=%q pools=%v", node.Addr, session.pool.hostConnPools) t.FailNow() } @@ -129,7 +129,7 @@ func TestEventNodeUp(t *testing.T) { t.Fatal(err) } - if _, ok := getPool(session.pool, node.ID); ok { + if _, ok := getPool(session.pool, node.HostID); ok { t.Fatal("node not removed after remove event") } @@ -140,11 +140,11 @@ func TestEventNodeUp(t *testing.T) { // cassandra < 2.2 needs 10 seconds to start up the binary service time.Sleep(15 * time.Second) - if _, ok := getPool(session.pool, node.ID); !ok { + if _, ok := getPool(session.pool, node.HostID); !ok { t.Fatal("node not added after node added event") } - host := session.ring.getHost(node.ID) + host := session.ring.getHost(node.HostID) if host == nil { t.Fatal("node not in metadata ring") } else if !host.IsUp() { @@ -164,13 +164,13 @@ func TestEventFilter(t *testing.T) { session := createSessionFromCluster(cluster, t) defer session.Close() - if _, ok := getPool(session.pool, whiteListedNode.ID); !ok { + if _, ok := getPool(session.pool, whiteListedNode.HostID); !ok { t.Errorf("should have %v in pool but dont", whiteListedNodeName) } - for _, host := range [...]string{"node2", "node3"} { - if _, ok := getPool(session.pool, cassNodes[host].ID); ok { - t.Errorf("should not have %v in pool", host) + for _, node := range [...]string{"node2", "node3"} { + if _, ok := getPool(session.pool, cassNodes[node].HostID); ok { + t.Errorf("should not have %v in pool", node) } } @@ -188,10 +188,10 @@ func TestEventFilter(t *testing.T) { t.Fatalf("couldn't restore a cluster : %v", err) } - for _, host := range [...]string{"node2", "node3"} { - _, ok := getPool(session.pool, cassNodes[host].ID) + for _, node := range [...]string{"node2", "node3"} { + _, ok := getPool(session.pool, cassNodes[node].HostID) if ok { - t.Errorf("should not have %v in pool", host) + t.Errorf("should not have %v in pool", node) } } @@ -211,7 +211,7 @@ func TestEventDownQueryable(t *testing.T) { session := createSessionFromCluster(cluster, t) defer session.Close() - if pool, ok := getPool(session.pool, targetNode.ID); !ok { + if pool, ok := getPool(session.pool, targetNode.HostID); !ok { t.Fatalf("should have %v in pool but dont", targetNode.Addr) } else if !pool.host.IsUp() { t.Fatalf("host is not up %v", pool.host) @@ -225,7 +225,7 @@ func TestEventDownQueryable(t *testing.T) { t.Fatalf("couldn't preserve a cluster : %v", err) } - if pool, ok := getPool(session.pool, targetNode.ID); !ok { + if pool, ok := getPool(session.pool, targetNode.HostID); !ok { t.Fatalf("should have %v in pool but dont", targetNode.Addr) } else if !pool.host.IsUp() { t.Fatalf("host is not up %v", pool.host) diff --git a/go.mod b/go.mod index 53ab9193e..d77722579 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,8 @@ module github.com/gocql/gocql go 1.23 require ( + github.com/bitly/go-hostpool v0.1.0 // indirect + github.com/docker/docker v27.1.1+incompatible // indirect github.com/golang/snappy v0.0.4 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed github.com/testcontainers/testcontainers-go v0.33.0 @@ -72,8 +74,3 @@ require ( golang.org/x/crypto v0.22.0 // indirect golang.org/x/sys v0.21.0 // indirect ) - -require ( - github.com/bitly/go-hostpool v0.1.0 // indirect - github.com/docker/docker v27.1.1+incompatible -) diff --git a/main_test.go b/main_test.go index 78223a2a4..d79ed6ef3 100644 --- a/main_test.go +++ b/main_test.go @@ -31,11 +31,9 @@ import ( "context" "flag" "fmt" - "io" "log" "os" "strconv" - "strings" "testing" "time" @@ -44,13 +42,14 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -type TChost struct { - TC testcontainers.Container - Addr string - ID string +type tcNode struct { + TC testcontainers.Container + Addr string + HostID string + CountRestart int } -var cassNodes = make(map[string]TChost) +var cassNodes = make(map[string]*tcNode) var networkName string func TestMain(m *testing.M) { @@ -72,8 +71,10 @@ func TestMain(m *testing.M) { log.Fatalf("Failed to start Cassandra node %d: %v", i, err) } } - // remove the last coma - *flagCluster = (*flagCluster)[:len(*flagCluster)-1] + + if err := assignHostID(); err != nil { + log.Fatalf("Failed to assign Cassandra host ID: %v", err) + } // run all tests code := m.Run() @@ -86,8 +87,8 @@ func NodeUpTC(ctx context.Context, number int) error { jvmOpts := "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" if *clusterSize == 1 { - // speeds up the creation of a single-node cluster. - jvmOpts += " -Dcassandra.initial_token=0 -Dcassandra.skip_wait_for_gossip_to_settle=0" + // speeds up the creation of a single-node cluster. not for topology tests + jvmOpts += " -Dcassandra.skip_wait_for_gossip_to_settle=0" } env := map[string]string{ @@ -105,10 +106,22 @@ func NodeUpTC(ctx context.Context, number int) error { env["AUTH_TEST"] = "true" } - fs := []testcontainers.ContainerFile{{}} + fs := []testcontainers.ContainerFile{ + { + HostFilePath: "./testdata/update_cas_config.sh", + ContainerFilePath: "/usr/local/bin/update_cas_config.sh", + FileMode: 0o777, + }, + { + HostFilePath: "./testdata/docker-entrypoint.sh", + ContainerFilePath: "/usr/local/bin/docker-entrypoint.sh", + FileMode: 0o777, + }, + } + if *flagRunSslTest { env["RUN_SSL_TEST"] = "true" - fs = []testcontainers.ContainerFile{ + fs = append(fs, []testcontainers.ContainerFile{ { HostFilePath: "./testdata/pki/.keystore", ContainerFilePath: "testdata/.keystore", @@ -119,59 +132,14 @@ func NodeUpTC(ctx context.Context, number int) error { ContainerFilePath: "testdata/.truststore", FileMode: 0o777, }, - { - HostFilePath: "update_container_cass_config.sh", - ContainerFilePath: "/update_container_cass_config.sh", - FileMode: 0o777, - }, - { - HostFilePath: "./testdata/pki/cqlshrc", - ContainerFilePath: "/root/.cassandra/cqlshrc", - FileMode: 0o777, - }, - { - HostFilePath: "./testdata/pki/gocql.crt", - ContainerFilePath: "/root/.cassandra/gocql.crt", - FileMode: 0o777, - }, - { - HostFilePath: "./testdata/pki/gocql.key", - ContainerFilePath: "/root/.cassandra/gocql.key", - FileMode: 0o777, - }, - { - HostFilePath: "./testdata/pki/ca.crt", - ContainerFilePath: "/root/.cassandra/ca.crt", - FileMode: 0o777, - }, - } + }...) } req := testcontainers.ContainerRequest{ - Image: "cassandra:" + cassandraVersion, - Env: env, - Files: fs, - Networks: []string{networkName}, - LifecycleHooks: []testcontainers.ContainerLifecycleHooks{{ - PostStarts: []testcontainers.ContainerHook{ - func(ctx context.Context, c testcontainers.Container) error { - // wait for cassandra config.yaml to initialize - time.Sleep(100 * time.Millisecond) - - _, body, err := c.Exec(ctx, []string{"bash", "./update_container_cass_config.sh"}) - if err != nil { - return err - } - - data, _ := io.ReadAll(body) - if ok := strings.Contains(string(data), "Cassandra configuration modified successfully."); !ok { - return fmt.Errorf("./update_container_cass_config.sh didn't complete successfully %v", string(data)) - } - - return nil - }, - }, - }}, + Image: "cassandra:" + cassandraVersion, + Env: env, + Files: fs, + Networks: []string{networkName}, WaitingFor: wait.ForLog("Startup complete").WithStartupTimeout(2 * time.Minute), Name: "node" + strconv.Itoa(number), } @@ -194,54 +162,47 @@ func NodeUpTC(ctx context.Context, number int) error { time.Sleep(10 * time.Second) } - hostID, err := getCassNodeID(ctx, container, cIP) - if err != nil { - return err - } - - cassNodes[req.Name] = TChost{ + cassNodes[req.Name] = &tcNode{ TC: container, Addr: cIP, - ID: hostID, } - *flagCluster += cIP + "," + *flagCluster += cIP + if *clusterSize > number { + *flagCluster += "," + } return nil } -func getCassNodeID(ctx context.Context, container testcontainers.Container, ip string) (string, error) { - var cmd []string - if *flagRunSslTest { - cmd = []string{"cqlsh", ip, "9042", "--ssl", "ip", "/root/.cassandra/cqlshrc", "-e", "SELECT host_id FROM system.local;"} - } else { - cmd = []string{"cqlsh", "-e", "SELECT host_id FROM system.local;"} - } - - _, reader, err := container.Exec(ctx, cmd) - if err != nil { - return "", fmt.Errorf("failed to execute cqlsh command: %v", err) +func assignHostID() error { + cluster := createCluster() + if *flagRunAuthTest { + cluster.Authenticator = PasswordAuthenticator{ + Username: "cassandra", + Password: "cassandra", + } } - b, err := io.ReadAll(reader) + session, err := cluster.CreateSession() if err != nil { - return "", err + return err } - output := string(b) - - lines := strings.Split(output, "\n") + defer session.Close() - if len(lines) < 4 { - return "", fmt.Errorf("unexpected output format, less than 4 lines: %v", lines) + for _, node := range cassNodes { + if host, ok := session.ring.getHostByIP(node.Addr); ok { + node.HostID = host.hostId + } else { + return fmt.Errorf("host_id for node addr: %s not found", node.Addr) + } } - hostID := strings.TrimSpace(lines[3]) - return hostID, nil + return nil } // restoreCluster is a helper function that ensures the cluster remains fully operational during topology changes. // Commonly used in test scenarios where nodes are added, removed, or modified to maintain cluster stability and prevent downtime. func restoreCluster(ctx context.Context) error { - var cmd []string for _, container := range cassNodes { if running := container.TC.IsRunning(); running { continue @@ -250,20 +211,17 @@ func restoreCluster(ctx context.Context) error { return fmt.Errorf("cannot start a container: %v", err) } - if *flagRunSslTest { - cmd = []string{"cqlsh", container.Addr, "9042", "--ssl", "ip", "/root/.cassandra/cqlshrc", "-e", "SELECT bootstrapped FROM system.local"} - } else { - cmd = []string{"cqlsh", "-e", "SELECT bootstrapped FROM system.local"} - } + container.CountRestart += 1 - err := wait.ForExec(cmd).WithResponseMatcher(func(body io.Reader) bool { - data, _ := io.ReadAll(body) - return strings.Contains(string(data), "COMPLETED") - }).WaitUntilReady(ctx, container.TC) + err := wait.ForLog("Startup complete"). + WithStartupTimeout(30*time.Second). + WithOccurrence(container.CountRestart+1). + WaitUntilReady(ctx, container.TC) if err != nil { - return fmt.Errorf("cannot wait until fully bootstrapped: %v", err) + return fmt.Errorf("cannot wait until a start container: %v", err) } - time.Sleep(5 * time.Second) + + time.Sleep(10 * time.Second) } return nil diff --git a/testdata/docker-entrypoint.sh b/testdata/docker-entrypoint.sh new file mode 100644 index 000000000..416fbb984 --- /dev/null +++ b/testdata/docker-entrypoint.sh @@ -0,0 +1,97 @@ +#!/bin/bash +set -e + +# first arg is `-f` or `--some-option` +# or there are no args +if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then + set -- cassandra -f "$@" +fi + +# allow the container to be started with `--user` +if [ "$1" = 'cassandra' -a "$(id -u)" = '0' ]; then + find "$CASSANDRA_CONF" /var/lib/cassandra /var/log/cassandra \ + \! -user cassandra -exec chown cassandra '{}' + + exec gosu cassandra "$BASH_SOURCE" "$@" +fi + +_ip_address() { + # scrape the first non-localhost IP address of the container + # in Swarm Mode, we often get two IPs -- the container IP, and the (shared) VIP, and the container IP should always be first + ip address | awk ' + $1 != "inet" { next } # only lines with ip addresses + $NF == "lo" { next } # skip loopback devices + $2 ~ /^127[.]/ { next } # skip loopback addresses + $2 ~ /^169[.]254[.]/ { next } # skip link-local addresses + { + gsub(/\/.+$/, "", $2) + print $2 + exit + } + ' +} + +# "sed -i", but without "mv" (which doesn't work on a bind-mounted file, for example) +_sed-in-place() { + local filename="$1"; shift + local tempFile + tempFile="$(mktemp)" + sed "$@" "$filename" > "$tempFile" + cat "$tempFile" > "$filename" + rm "$tempFile" +} + +if [ "$1" = 'cassandra' ]; then + : ${CASSANDRA_RPC_ADDRESS='0.0.0.0'} + + : ${CASSANDRA_LISTEN_ADDRESS='auto'} + if [ "$CASSANDRA_LISTEN_ADDRESS" = 'auto' ]; then + CASSANDRA_LISTEN_ADDRESS="$(_ip_address)" + fi + + : ${CASSANDRA_BROADCAST_ADDRESS="$CASSANDRA_LISTEN_ADDRESS"} + + if [ "$CASSANDRA_BROADCAST_ADDRESS" = 'auto' ]; then + CASSANDRA_BROADCAST_ADDRESS="$(_ip_address)" + fi + : ${CASSANDRA_BROADCAST_RPC_ADDRESS:=$CASSANDRA_BROADCAST_ADDRESS} + + if [ -n "${CASSANDRA_NAME:+1}" ]; then + : ${CASSANDRA_SEEDS:="cassandra"} + fi + : ${CASSANDRA_SEEDS:="$CASSANDRA_BROADCAST_ADDRESS"} + + _sed-in-place "$CASSANDRA_CONF/cassandra.yaml" \ + -r 's/(- seeds:).*/\1 "'"$CASSANDRA_SEEDS"'"/' + + for yaml in \ + broadcast_address \ + broadcast_rpc_address \ + cluster_name \ + endpoint_snitch \ + listen_address \ + num_tokens \ + rpc_address \ + start_rpc \ + ; do + var="CASSANDRA_${yaml^^}" + val="${!var}" + if [ "$val" ]; then + _sed-in-place "$CASSANDRA_CONF/cassandra.yaml" \ + -r 's/^(# )?('"$yaml"':).*/\2 '"$val"'/' + fi + done + + for rackdc in dc rack; do + var="CASSANDRA_${rackdc^^}" + val="${!var}" + if [ "$val" ]; then + _sed-in-place "$CASSANDRA_CONF/cassandra-rackdc.properties" \ + -r 's/^('"$rackdc"'=).*/\1 '"$val"'/' + fi + done +fi + +# execute custom script +./usr/local/bin/update_cas_config.sh + +exec "$@" diff --git a/testdata/pki/cqlshrc b/testdata/pki/cqlshrc deleted file mode 100644 index 9939dda67..000000000 --- a/testdata/pki/cqlshrc +++ /dev/null @@ -1,13 +0,0 @@ -[ssl] -certfile = /root/.cassandra/gocql.crt -userkey = /root/.cassandra/gocql.key -usercert = /root/.cassandra/gocql.crt -ca_certs = /root/.cassandra/ca.crt -validate = false - -[connection] -factory = cqlshlib.ssl.ssl_transport_factory - -[authentication] -username = cassandra -password = cassandra diff --git a/update_container_cass_config.sh b/testdata/update_cas_config.sh similarity index 83% rename from update_container_cass_config.sh rename to testdata/update_cas_config.sh index c3bcf0611..605056f89 100755 --- a/update_container_cass_config.sh +++ b/testdata/update_cas_config.sh @@ -16,7 +16,7 @@ update_property() { elif [[ $CASS_VERSION == 4.1.* ]]; then indent=" " else - indent=" " + indent=" " fi if grep -q "^${property}:" "$CASSANDRA_CONFIG"; then @@ -42,7 +42,7 @@ update_property() { next } { print $0 } - ' "$CASSANDRA_CONFIG" > tmpfile && mv tmpfile "$CASSANDRA_CONFIG" + ' "$CASSANDRA_CONFIG" > /tmp/tmpfile && mv /tmp/tmpfile "$CASSANDRA_CONFIG" fi else # Add new root property with nested property @@ -55,6 +55,7 @@ update_property() { fi } +# custom script started # Function to configure Cassandra based on the version configure_cassandra() { local keypath="testdata" @@ -64,11 +65,18 @@ configure_cassandra() { ) if [[ $AUTH_TEST == true ]]; then + if [[ $CASS_VERSION == 5.*.* ]]; then + conf+=( + "authenticator.class_name :org.apache.cassandra.auth.PasswordAuthenticator" + "authorizer: CassandraAuthorizer" + ) + else conf+=( "authenticator: PasswordAuthenticator" "authorizer: CassandraAuthorizer" ) fi +fi if [[ $RUN_SSL_TEST == true ]]; then conf+=( @@ -111,15 +119,14 @@ configure_cassandra() { IFS=":" read -r property value <<< "$setting" update_property "$property" "$value" done -} -# update Cassandra config -configure_cassandra - -# Update rpc addresses with the container's IP address -IP_ADDRESS=$(hostname -i) -sed -i "s/^rpc_address:.*/rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml -sed -i "s/^# broadcast_rpc_address:.*/broadcast_rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml + # Update rpc addresses with the container's IP address + IP_ADDRESS=$(hostname -i) + sed -i "s/^rpc_address:.*/rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml + sed -i "s/^# broadcast_rpc_address:.*/broadcast_rpc_address: $IP_ADDRESS/" /etc/cassandra/cassandra.yaml -echo "Cassandra configuration modified successfully." + echo "Cassandra configuration modified successfully." +} +## update Cassandra config +configure_cassandra From 8887c189dc747743a239f4dc3334f6ef1af9c6e4 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Wed, 18 Sep 2024 15:59:40 +0300 Subject: [PATCH 07/10] Remove the CCM test integration runner and related components from the driver --- control_ccm_test.go => control_tc_test.go | 0 events_ccm_test.go => events_tc_test.go | 0 install_test_deps.sh | 29 ---- integration.sh | 114 ------------ internal/ccm/ccm.go | 202 ---------------------- internal/ccm/ccm_test.go | 73 -------- main_test.go | 1 - testdata/update_cas_config.sh | 1 - 8 files changed, 420 deletions(-) rename control_ccm_test.go => control_tc_test.go (100%) rename events_ccm_test.go => events_tc_test.go (100%) delete mode 100755 install_test_deps.sh delete mode 100755 integration.sh delete mode 100644 internal/ccm/ccm.go delete mode 100644 internal/ccm/ccm_test.go diff --git a/control_ccm_test.go b/control_tc_test.go similarity index 100% rename from control_ccm_test.go rename to control_tc_test.go diff --git a/events_ccm_test.go b/events_tc_test.go similarity index 100% rename from events_ccm_test.go rename to events_tc_test.go diff --git a/install_test_deps.sh b/install_test_deps.sh deleted file mode 100755 index 048f768bc..000000000 --- a/install_test_deps.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -set -x - -# This is not supposed to be an error-prone script; just a convenience. - -# Install CCM -pip install -i https://pypi.org/simple --user cql PyYAML six psutil -git clone https://github.com/pcmanus/ccm.git -pushd ccm -./setup.py install --user -popd diff --git a/integration.sh b/integration.sh deleted file mode 100755 index b61f0ff48..000000000 --- a/integration.sh +++ /dev/null @@ -1,114 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -set -eux - -function run_tests() { - local clusterSize=3 - local version=$1 - local auth=$2 - local compressor=$3 - - if [ "$auth" = true ]; then - clusterSize=1 - fi - - local keypath="$(pwd)/testdata/pki" - - local conf=( - "client_encryption_options.enabled: true" - "client_encryption_options.keystore: $keypath/.keystore" - "client_encryption_options.keystore_password: cassandra" - "client_encryption_options.require_client_auth: true" - "client_encryption_options.truststore: $keypath/.truststore" - "client_encryption_options.truststore_password: cassandra" - "concurrent_reads: 2" - "concurrent_writes: 2" - "rpc_server_type: sync" - "rpc_min_threads: 2" - "rpc_max_threads: 2" - "write_request_timeout_in_ms: 5000" - "read_request_timeout_in_ms: 5000" - ) - - ccm remove test || true - - ccm create test -v $version -n $clusterSize -d --vnodes --jvm_arg="-Xmx256m -XX:NewSize=100m" - ccm updateconf "${conf[@]}" - - if [ "$auth" = true ] - then - ccm updateconf 'authenticator: PasswordAuthenticator' 'authorizer: CassandraAuthorizer' - rm -rf $HOME/.ccm/test/node1/data/system_auth - fi - - local proto=2 - if [[ $version == 1.2.* ]]; then - proto=1 - elif [[ $version == 2.0.* ]]; then - proto=2 - elif [[ $version == 2.1.* ]]; then - proto=3 - elif [[ $version == 2.2.* || $version == 3.0.* ]]; then - proto=4 - ccm updateconf 'enable_user_defined_functions: true' - export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" - elif [[ $version == 3.*.* ]]; then - proto=5 - ccm updateconf 'enable_user_defined_functions: true' - export JVM_EXTRA_OPTS=" -Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" - fi - - sleep 1s - - ccm list - ccm start --wait-for-binary-proto - ccm status - ccm node1 nodetool status - - local args="-gocql.timeout=60s -runssl -proto=$proto -rf=3 -clusterSize=$clusterSize -autowait=2000ms -compressor=$compressor -gocql.cversion=$version -cluster=$(ccm liveset) ./..." - - go test -v -tags unit -race - - if [ "$auth" = true ] - then - sleep 30s - go test -run=TestAuthentication -tags "integration gocql_debug" -timeout=15s -runauth $args - else - sleep 1s - go test -tags "cassandra gocql_debug" -timeout=5m -race $args - - ccm clear - ccm start --wait-for-binary-proto - sleep 1s - - go test -tags "integration gocql_debug" -timeout=5m -race $args - - ccm clear - ccm start --wait-for-binary-proto - sleep 1s - - go test -tags "ccm gocql_debug" -timeout=5m -race $args - fi - - ccm remove -} - -run_tests $1 $2 $3 diff --git a/internal/ccm/ccm.go b/internal/ccm/ccm.go deleted file mode 100644 index 55b540158..000000000 --- a/internal/ccm/ccm.go +++ /dev/null @@ -1,202 +0,0 @@ -//go:build ccm -// +build ccm - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 - * Copyright (c) 2016, The Gocql authors, - * provided under the BSD-3-Clause License. - * See the NOTICE file distributed with this work for additional information. - */ - -package ccm - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "os/exec" - "runtime" - "strings" -) - -func execCmd(args ...string) (*bytes.Buffer, error) { - execName := "ccm" - if runtime.GOOS == "windows" { - args = append([]string{"/c", execName}, args...) - execName = "cmd.exe" - } - cmd := exec.Command(execName, args...) - stdout := &bytes.Buffer{} - cmd.Stdout = stdout - cmd.Stderr = &bytes.Buffer{} - if err := cmd.Run(); err != nil { - return nil, errors.New(cmd.Stderr.(*bytes.Buffer).String()) - } - - return stdout, nil -} - -func AllUp() error { - status, err := Status() - if err != nil { - return err - } - - for _, host := range status { - if !host.State.IsUp() { - if err := NodeUp(host.Name); err != nil { - return err - } - } - } - - return nil -} - -func NodeUp(node string) error { - args := []string{node, "start", "--wait-for-binary-proto"} - if runtime.GOOS == "windows" { - args = append(args, "--quiet-windows") - } - _, err := execCmd(args...) - return err -} - -func NodeDown(node string) error { - _, err := execCmd(node, "stop") - return err -} - -type Host struct { - State NodeState - Addr string - Name string -} - -type NodeState int - -func (n NodeState) String() string { - if n == NodeStateUp { - return "UP" - } else if n == NodeStateDown { - return "DOWN" - } else { - return fmt.Sprintf("UNKNOWN_STATE_%d", n) - } -} - -func (n NodeState) IsUp() bool { - return n == NodeStateUp -} - -const ( - NodeStateUp NodeState = iota - NodeStateDown -) - -func Status() (map[string]Host, error) { - // TODO: parse into struct to manipulate - out, err := execCmd("status", "-v") - if err != nil { - return nil, err - } - - const ( - stateCluster = iota - stateCommas - stateNode - stateOption - ) - - nodes := make(map[string]Host) - // didnt really want to write a full state machine parser - state := stateCluster - sc := bufio.NewScanner(out) - - var host Host - - for sc.Scan() { - switch state { - case stateCluster: - text := sc.Text() - if !strings.HasPrefix(text, "Cluster:") { - return nil, fmt.Errorf("expected 'Cluster:' got %q", text) - } - state = stateCommas - case stateCommas: - text := sc.Text() - if !strings.HasPrefix(text, "-") { - return nil, fmt.Errorf("expected commas got %q", text) - } - state = stateNode - case stateNode: - // assume nodes start with node - text := sc.Text() - if !strings.HasPrefix(text, "node") { - return nil, fmt.Errorf("expected 'node' got %q", text) - } - line := strings.Split(text, ":") - host.Name = line[0] - - nodeState := strings.TrimSpace(line[1]) - switch nodeState { - case "UP": - host.State = NodeStateUp - case "DOWN": - host.State = NodeStateDown - default: - return nil, fmt.Errorf("unknown node state from ccm: %q", nodeState) - } - - state = stateOption - case stateOption: - text := sc.Text() - if text == "" { - state = stateNode - nodes[host.Name] = host - host = Host{} - continue - } - - line := strings.Split(strings.TrimSpace(text), "=") - k, v := line[0], line[1] - if k == "binary" { - // could check errors - // ('127.0.0.1', 9042) - v = v[2:] // ('' - if i := strings.IndexByte(v, '\''); i < 0 { - return nil, fmt.Errorf("invalid binary v=%q", v) - } else { - host.Addr = v[:i] - // dont need port - } - } - default: - return nil, fmt.Errorf("unexpected state: %q", state) - } - } - - if err := sc.Err(); err != nil { - return nil, fmt.Errorf("unable to parse ccm status: %v", err) - } - - return nodes, nil -} diff --git a/internal/ccm/ccm_test.go b/internal/ccm/ccm_test.go deleted file mode 100644 index b8fa9efce..000000000 --- a/internal/ccm/ccm_test.go +++ /dev/null @@ -1,73 +0,0 @@ -//go:build ccm -// +build ccm - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40 - * Copyright (c) 2016, The Gocql authors, - * provided under the BSD-3-Clause License. - * See the NOTICE file distributed with this work for additional information. - */ - -package ccm - -import ( - "testing" -) - -func TestCCM(t *testing.T) { - if err := AllUp(); err != nil { - t.Fatal(err) - } - - status, err := Status() - if err != nil { - t.Fatal(err) - } - - if host, ok := status["node1"]; !ok { - t.Fatal("node1 not in status list") - } else if !host.State.IsUp() { - t.Fatal("node1 is not up") - } - - NodeDown("node1") - status, err = Status() - if err != nil { - t.Fatal(err) - } - - if host, ok := status["node1"]; !ok { - t.Fatal("node1 not in status list") - } else if host.State.IsUp() { - t.Fatal("node1 is not down") - } - - NodeUp("node1") - status, err = Status() - if err != nil { - t.Fatal(err) - } - - if host, ok := status["node1"]; !ok { - t.Fatal("node1 not in status list") - } else if !host.State.IsUp() { - t.Fatal("node1 is not up") - } -} diff --git a/main_test.go b/main_test.go index d79ed6ef3..da5680d2f 100644 --- a/main_test.go +++ b/main_test.go @@ -87,7 +87,6 @@ func NodeUpTC(ctx context.Context, number int) error { jvmOpts := "-Dcassandra.test.fail_writes_ks=test -Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler" if *clusterSize == 1 { - // speeds up the creation of a single-node cluster. not for topology tests jvmOpts += " -Dcassandra.skip_wait_for_gossip_to_settle=0" } diff --git a/testdata/update_cas_config.sh b/testdata/update_cas_config.sh index 605056f89..5792a5cd7 100755 --- a/testdata/update_cas_config.sh +++ b/testdata/update_cas_config.sh @@ -55,7 +55,6 @@ update_property() { fi } -# custom script started # Function to configure Cassandra based on the version configure_cassandra() { local keypath="testdata" From 9fa9ab54d1f3cfe9e64c6c9f5f26296e1a3ca752 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Fri, 20 Sep 2024 14:52:48 +0300 Subject: [PATCH 08/10] minor fix --- .github/workflows/main.yml | 6 ++---- testdata/update_cas_config.sh | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 125701204..5f0bb7400 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,8 +41,7 @@ jobs: go-version: ${{ matrix.go }} - name: setup run: | - # todo: back the -runssl flag, as soon as the certs get updated. - args="-gocql.timeout=60s -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." + args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=3 -autowait=2000ms -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }} ./..." echo "args=$args" >> $GITHUB_ENV - name: run run: | @@ -64,8 +63,7 @@ jobs: go-version: ${{ matrix.go }} - name: setup run: | - # todo: return back the -runssl flag, as soon as the certs get updated. - args="-gocql.timeout=60s -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }}" + args="-gocql.timeout=60s -runssl -proto=4 -rf=3 -clusterSize=1 -autowait=2000ms -runauth -compressor=${{ matrix.compressor }} -gocql.cversion=${{ matrix.cassandra_version }}" echo "args=$args" >> $GITHUB_ENV - name: run run: | diff --git a/testdata/update_cas_config.sh b/testdata/update_cas_config.sh index 5792a5cd7..89469c02f 100755 --- a/testdata/update_cas_config.sh +++ b/testdata/update_cas_config.sh @@ -13,8 +13,6 @@ update_property() { local indent="" if [[ $CASS_VERSION == 4.0.* ]]; then indent=" " - elif [[ $CASS_VERSION == 4.1.* ]]; then - indent=" " else indent=" " fi @@ -22,7 +20,6 @@ update_property() { if grep -q "^${property}:" "$CASSANDRA_CONFIG"; then # If the property exists, update its value sed -i "s|^\(${property}:\).*|\1 ${value}|" "$CASSANDRA_CONFIG" -# echo "Updated $property to $value" else if [[ "$property" == *"."* ]]; then # If it's a nested property From 737f41554050811b692c692f4537b599b85420b8 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Fri, 20 Sep 2024 16:35:37 +0300 Subject: [PATCH 09/10] Increasing the timeout duration for cluster recovery. --- main_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main_test.go b/main_test.go index da5680d2f..9f65af9c6 100644 --- a/main_test.go +++ b/main_test.go @@ -213,7 +213,7 @@ func restoreCluster(ctx context.Context) error { container.CountRestart += 1 err := wait.ForLog("Startup complete"). - WithStartupTimeout(30*time.Second). + WithStartupTimeout(60*time.Second). WithOccurrence(container.CountRestart+1). WaitUntilReady(ctx, container.TC) if err != nil { From 9c34737f8683628cdddbc6e6a99eff0d01051613 Mon Sep 17 00:00:00 2001 From: Bychkov Date: Tue, 15 Oct 2024 22:40:38 +0300 Subject: [PATCH 10/10] test:connect all nodes --- go.mod | 4 ++-- integration_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d77722579..ff24cd732 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,6 @@ module github.com/gocql/gocql go 1.23 require ( - github.com/bitly/go-hostpool v0.1.0 // indirect - github.com/docker/docker v27.1.1+incompatible // indirect github.com/golang/snappy v0.0.4 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed github.com/testcontainers/testcontainers-go v0.33.0 @@ -32,6 +30,7 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/bitly/go-hostpool v0.1.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/containerd/containerd v1.7.18 // indirect @@ -39,6 +38,7 @@ require ( github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v27.1.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect diff --git a/integration_test.go b/integration_test.go index 3622dfbd6..8c1466bdf 100644 --- a/integration_test.go +++ b/integration_test.go @@ -272,3 +272,28 @@ func TestUDF(t *testing.T) { t.Fatal(err) } } + +func TestAllNodesConnected(t *testing.T) { + cluster := createCluster() + cluster.PoolConfig.HostSelectionPolicy = RoundRobinHostPolicy() + + session := createSessionFromCluster(cluster, t) + defer session.Close() + + ids := make(map[string]bool) + + // Loop to query system.local multiple times. If there is a cluster with more than 10 nodes add to the loop more iterations + for i := 0; i < 10; i++ { + var hostID string + err := session.Query("SELECT host_id FROM system.local").Scan(&hostID) + if err != nil { + t.Fatal(err) + } + + ids[hostID] = true + } + + if *clusterSize != len(ids) { + t.Fatalf("Expected to connect to %d unique nodes", *clusterSize) + } +}